Valerie Wong
12/23/2025, 8:12 PMkapa.ai
12/23/2025, 8:12 PMkapa.ai
12/23/2025, 8:12 PMgenerate_schema_name macro. ### 1. Basic config in dbt_project.yml If you just want a dedicated Elementary schema that follows dbt’s default pattern (<target_schema>_elementary), add: yml models: elementary: +schema: elementary This makes Elementary models land in a schema like TARGETSCHEMA_elementary. [[Elementary schema](https://docs.elementary-data.com/data-tests/dbt/dbt-package#page-title)] ### 2. Using a fully custom schema name If you want full control (e.g. elementary_data_observability or a different suffix), override generate_schema_name and use `meta.schema_name`: sql -- macros/generate_schema_name.sql {% macro generate_schema_name(custom_schema_name, node) -%} {%- set default_schema = target.schema -%} {% set config_meta = node.config.get('meta') %} {% if config_meta and config_meta is mapping %} {% set schema_name = config_meta.get('schema_name') %} {% if schema_name and schema_name is string %} {{ return(schema_name) }} {% endif %} {%- elif custom_schema_name is none -%} {{ default_schema }} {%- else -%} {{ default_schema }}_{{ custom_schema_name | trim }} {%- endif -%} {%- endmacro %} Then configure Elementary to use that explicit schema: yml models: elementary: +meta: schema_name: "my_custom_elementary_suffix" This will create all Elementary models in the schema my_custom_elementary_suffix (no automatic prefix/suffix added). [[OSS FAQ – change schema](https://docs.elementary-data.com/oss/general/faq#page-title)] ### 3. If you already have a custom generate_schema_name If your project already overrides generate_schema_name, you can: - Either adapt it so that when node.package_name == 'elementary' you return the exact schema you want, or - Use the meta.schema_name pattern above and keep your existing logic for everything else. If you share your current generate_schema_name macro and desired final schema (e.g. DBT_ELEMENTARY, analytics_elementary, etc.), I can show the minimal change needed.Valerie Wong
12/23/2025, 8:14 PMkapa.ai
12/23/2025, 8:14 PMkapa.ai
12/23/2025, 8:15 PMValerie Wong
12/23/2025, 8:15 PMkapa.ai
12/23/2025, 8:15 PMkapa.ai
12/23/2025, 8:15 PMdbt test succeeds. You can walk through these checks: --- ### 1. Elementary models not run (or run on a different target) Elementary tables are only created/populated after: bash dbt run --select elementary If you ran this on a different --target than your dbt test, the hooks will try to insert into tables that don’t exist in the current target, so they stay empty. Run both on the same target, e.g.: bash dbt run --select elementary --target prod dbt test --target prod [[Slack – non‑existent table](https://elementary-community.slack.com/archives/C02CTC89LAX/p1683764076675589?thread_ts=1683764076.675589&cid=C02CTC89LAX); [Cloud troubleshoot](https://docs.elementary-data.com/cloud/guides/troubleshoot#page-title)] --- ### 2. No tests actually ran If dbt test prints Nothing to do, no tests executed, so elementary_test_results will be empty. You must define dbt tests (generic or singular) on your models first. [[Empty tests](https://elementary-community.slack.com/archives/C02CTC89LAX/p1706612460738369?thread_ts=1706612460.738369&cid=C02CTC89LAX)] --- ### 3. Wrong materialization (tables/views instead of incremental) elementary_test_results must be incremental. If a global config like: yml models: +materialized: table overrides Elementary’s materializations, Elementary can’t append results and tables may stay empty or error. Fix by scoping that config to your own project only, not to all packages, then recreate Elementary models: bash dbt run --select elementary --full-refresh dbt test [[OSS troubleshooting](https://docs.elementary-data.com/oss/general/troubleshooting#page-title); [Model_run_results issue](https://elementary-community.slack.com/archives/C02CTC89LAX/p1693825818714329?thread_ts=1693825818.714329&cid=C02CTC89LAX)] --- ### 4. Hooks disabled via vars If any of these vars are set, Elementary won’t upload results, so tables stay empty even though tests pass: yml vars: disable_run_results: true disable_tests_results: true disable_dbt_invocation_autoupload: true disable_dbt_artifacts_autoupload: true Remove or set them to false and rerun: bash dbt run --select elementary dbt test [[Disabled vars](https://elementary-community.slack.com/archives/C02CTC89LAX/p1699310045488249?thread_ts=1699310045.488249&cid=C02CTC89LAX); [Hooks note](https://elementary-community.slack.com/archives/C02CTC89LAX/p1703824109693079?thread_ts=1703824109.693079&cid=C02CTC89LAX)] --- ### 5. On‑run‑end hooks not firing (or failing earlier) Elementary uploads artifacts and test results in on‑run‑end hooks. If another on‑run‑end hook fails first, dbt won’t execute Elementary’s hook, so no rows are inserted. [[On‑run‑end behavior](https://elementary-community.slack.com/archives/C02CTC89LAX/p1722936228529189?thread_ts=1722936228.529189&cid=C02CTC89LAX); [Hooks explanation](https://elementary-community.slack.com/archives/C02CTC89LAX/p1703824109693079?thread_ts=1703824109.693079&cid=C02CTC89LAX)] Check your dbt.log for lines like: text Elementary: Uploading test results. Elementary: Uploading run results. If they’re missing, the hooks didn’t run successfully. --- ### 6. Schema / generate_schema_name mismatch If you override generate_schema_name, Elementary tables may be created in a different schema than you expect, and the hooks may be writing to (or looking for) another schema. This can make it look like tables are “empty” when you’re just querying the wrong schema. [[Schema override issue](https://elementary-community.slack.com/archives/C02CTC89LAX/p1712851926036669?thread_ts=1712851926.036669&cid=C02CTC89LAX); [Another schema issue](https://elementary-community.slack.com/archives/C02CTC89LAX/p1685020975522279?thread_ts=1685020975.522279&cid=C02CTC89LAX)] Confirm: - The schema configured for models: elementary: in dbt_project.yml. - Your custom generate_schema_name macro doesn’t redirect Elementary models elsewhere. - You’re querying the same schema where dbt run --select elementary actually built the models. --- ### 7. Incremental model got “stuck” Occasionally the incremental elementary_test_results model can get into a bad state and stop appending. In that case, do a full refresh with the Elementary var: bash dbt run --select elementary --full-refresh --vars '{ "elementary_full_refresh": true }' dbt test [[Incremental fix](https://elementary-community.slack.com/archives/C02CTC89LAX/p1736544876896189?thread_ts=1736544876.896189&cid=C02CTC89LAX)] --- If you go through these and still see empty tables, the docs recommend checking elementary_test_results existence/materialization and then sharing dbt.log with the Elementary team. [[OSS troubleshooting](https://docs.elementary-data.com/oss/general/troubleshooting#page-title); [Cloud troubleshoot](https://docs.elementary-data.com/cloud/guides/troubleshoot#page-title)]Valerie Wong
12/23/2025, 8:16 PMkapa.ai
12/23/2025, 8:16 PMkapa.ai
12/23/2025, 8:16 PMcategory column over time, use the elementary.dimension_anomalies test with dimensions set to that column. ### Basic setup (table-level test) In your schema.yml (or equivalent): yml version: 2 models: - name: your_model_name config: elementary: timestamp_column: event_time # recommended, but optional data_tests: - elementary.dimension_anomalies: arguments: dimensions: - category # optional filters & time config: # where_expression: "category is not null" # time_bucket: # period: day # count: 1 This test: - Counts rows grouped by category. - Monitors how the frequency/distribution of each category value changes over time. - Works best when category has low cardinality. [[Dimension anomalies intro](https://docs.elementary-data.com/data-tests/anomaly-detection-tests/dimension-anomalies); [Dimensions config](https://docs.elementary-data.com/data-tests/anomaly-detection-configuration/dimensions)] ### Minimal version without timestamp If you don’t have a timestamp column: yml models: - name: your_model_name data_tests: - elementary.dimension_anomalies: arguments: dimensions: - category Without timestamp_column, Elementary monitors total row counts per category (no time buckets). [[Add tests examples](https://docs.elementary-data.com/data-tests/add-elementary-tests#adding-tests-examples); [Dimension anomalies behavior](https://docs.elementary-data.com/data-tests/anomaly-detection-tests/dimension-anomalies)] Run it with: bash dbt test -m your_model_name If you share your model name and timestamp column (if any), I can adapt this snippet exactly to your case.Valerie Wong
12/23/2025, 8:17 PMkapa.ai
12/23/2025, 8:18 PMkapa.ai
12/23/2025, 8:18 PMValerie Wong
12/23/2025, 8:18 PMkapa.ai
12/23/2025, 8:18 PMkapa.ai
12/23/2025, 8:18 PMignore_small_changes configuration on your elementary.volume_anomalies test. ignore_small_changes makes the test fail only if both: 1. The value is statistically anomalous (z‑score based), and 2. The change vs. the training-period mean is larger than your percent thresholds. [[ignore_small_changes](https://docs.elementary-data.com/data-tests/anomaly-detection-configuration/ignore_small_changes)] To ignore fluctuations under 10% (for both spikes and drops), configure: yml models: - name: your_model data_tests: - elementary.volume_anomalies: arguments: ignore_small_changes: spike_failure_percent_threshold: 10 drop_failure_percent_threshold: 10 With this setup, a volume anomaly will only fail if: - It’s flagged as anomalous by the model, and - It’s more than 10% higher (spike) or 10% lower (drop) than the mean in the training period. [[ignore_small_changes](https://docs.elementary-data.com/data-tests/anomaly-detection-configuration/ignore_small_changes); [volume_anomalies config](https://docs.elementary-data.com/data-tests/anomaly-detection-tests/volume-anomalies#test-configuration)]Valerie Wong
12/23/2025, 8:19 PMkapa.ai
12/23/2025, 8:19 PMkapa.ai
12/23/2025, 8:19 PMon-run-end hook is trying to read/write tables or schemas that your BigQuery user doesn’t have access to. The fix is either to grant the right permissions or to disable Elementary’s artifact uploads where you don’t need them. ### 1. Check what the error is about From the examples in BigQuery/Snowflake, the failing objects are usually: - Elementary artifacts tables: DBT_MODELS, DBT_TESTS, DBT_RUN_RESULTS, DATA_MONITORING_METRICS, etc. [[Snowflake perms example](https://elementary-community.slack.com/archives/C02CTC89LAX/p1682612682384909?thread_ts=1682612682.384909&cid=C02CTC89LAX); [Artifacts upload explanation](https://elementary-community.slack.com/archives/C02CTC89LAX/p1682612682384909?thread_ts=1682612682.384909&cid=C02CTC89LAX)] - Or the Elementary schema itself (e.g. elementary / *_elementary). [[Insufficient privileges elementary tables](https://elementary-community.slack.com/archives/C02CTC89LAX/p1695999713662539?thread_ts=1695999713.662539&cid=C02CTC89LAX)] Look at the exact table/schema in the error message and confirm your dbt service account can: - Read all project schemas - Write to the Elementary schema - Create the Elementary schema (or you create it up front) [[Elementary in prod – permissions](https://docs.elementary-data.com/oss/deployment-and-configuration/elementary-in-production#page-title)] If this is a prod job, the recommended fix is to grant those permissions. --- ### 2. If you don’t want Elementary to run in this job (CI, seed, non‑prod) You can disable Elementary’s models or its artifact uploads so the on-run-end hook doesn’t try to touch those tables. #### Option A – Disable Elementary models for certain targets In `dbt_project.yml`: yml models: elementary: +schema: "elementary" +enabled: "{{ target.name in ['prod'] }}" This runs Elementary only when target.name == 'prod'. [[Enable only in prod](https://elementary-community.slack.com/archives/C02CTC89LAX/p1678899522071399?thread_ts=1678899522.071399&cid=C02CTC89LAX)] For dbt seed specifically, you can also disable Elementary when the command is `seed`: yml models: elementary: +enabled: "{{ flags.WHICH != 'seed' }}" +schema: elementary [[Disable for seed](https://elementary-community.slack.com/archives/C02CTC89LAX/p1682612682384909?thread_ts=1682612682.384909&cid=C02CTC89LAX)] #### Option B – Keep models, but turn off artifact uploads in this env If you use Elementary only in prod and want CI/non‑prod to skip uploads, set vars: yml vars: disable_dbt_artifacts_autoupload: true disable_run_results: true disable_tests_results: true disable_dbt_invocation_autoupload: "{{ target.name != 'prod' }}" This stops the on-run-end hook from updating DATA_MONITORING_METRICS, DBT_MODELS, etc., which removes the permission requirement in those jobs. [[Vars to disable uploads](https://elementary-community.slack.com/archives/C02CTC89LAX/p1697606690660449?thread_ts=1697606690.660449&cid=C02CTC89LAX)] --- ### 3. If the error is about accessing INFORMATION_SCHEMA / external projects If the error mentions INFORMATION_SCHEMA or datasets in other projects you don’t control, you can temporarily disable the metadata models: yml models: elementary: edr: dbt_artifacts: dbt_columns: +enabled: false metadata_store: +enabled: false These are optional models; disabling them avoids information‑schema permissions issues. [[Disable metadata_store/dbt_columns](https://elementary-community.slack.com/archives/C02CTC89LAX/p1684375323318529?thread_ts=1684375323.318529&cid=C02CTC89LAX)] --- If you paste the exact BigQuery error text (table/schema name and role), I can point to the minimal change: grant a specific permission vs. disable a specific Elementary piece in that environment.Valerie Wong
12/23/2025, 8:25 PMkapa.ai
12/23/2025, 8:25 PMkapa.ai
12/23/2025, 8:25 PMedr monitor selectors (per‑channel runs) Tag your models in dbt, then run edr monitor once per tag/channel: yml models: - name: my_finance_model tags: ["finance"] Then route alerts for that tag to a specific channel: bash edr monitor --select tag:finance --slack-channel-name finance_data_ops edr monitor --select tag:marketing --slack-channel-name marketing_data_ops Each command sends alerts only for models/tests matching the tag selector to the given Slack channel. [[Tag routing example](https://elementary-community.slack.com/archives/C02CTC89LAX/p1690447538330909?thread_ts=1690447538.330909&cid=C02CTC89LAX); [Selectors & channels](https://elementary-community.slack.com/archives/C02CTC89LAX/p1699185769367119?thread_ts=1699185769.367119&cid=C02CTC89LAX)] > Note: run these edr monitor commands sequentially, not in parallel, to avoid locks on the alerts status table. [[Selectors note](https://elementary-community.slack.com/archives/C02CTC89LAX/p1690447538330909?thread_ts=1690447538.330909&cid=C02CTC89LAX)] --- ## Option 2 – Configure custom channels in dbt metadata (no per‑tag run needed) Instead of routing by tag at runtime, you can hard‑wire the Slack channel in dbt config using meta.channel. For example, if your project folders align with domains: yml models: finance: +meta: channel: finance_data_ops marketing: +meta: channel: marketing_data_ops All model and test alerts under models/finance go to #finance_data_ops, etc. [[Folder‑based channels](https://elementary-community.slack.com/archives/C02CTC89LAX/p1699185769367119?thread_ts=1699185769.367119&cid=C02CTC89LAX); [Custom channel docs](https://docs.elementary-data.com/oss/guides/alerts/alerts-configuration#alerts-distribution)] You can also set it at the test path level: yml tests: finance: +meta: channel: finance_data_ops With this approach you run a single edr monitor and Elementary routes alerts based on the configured meta.channel. [[Routing explanation](https://elementary-community.slack.com/archives/C02CTC89LAX/p1699185769367119?thread_ts=1699185769.367119&cid=C02CTC89LAX)] --- If you tell me your exact tag (e.g. tag:finance) and desired Slack channel name, I can give you the precise edr monitor command or dbt_project.yml snippet.Valerie Wong
12/23/2025, 8:28 PMkapa.ai
12/23/2025, 8:29 PMkapa.ai
12/23/2025, 8:29 PMdbt_project.yml This gives Elementary its own schema (usually <target_schema>_elementary): yml models: ## your project models my_project: # your configs here ## Elementary models elementary: +schema: "elementary" Depending on your generate_schema_name macro, this will create the schema JAFFLE_SHOP_STAGE_ELEMENTARY or similar in Snowflake. [[Elementary schema](https://docs.elementary-data.com/data-tests/dbt/dbt-package#page-title); [Quickstart dbt package](https://docs.elementary-data.com/data-tests/dbt/quickstart-package#page-title)] 2. Make sure global materializations don’t override Elementary If you have a global config like: yml models: my_project: materialized: "{{ 'table' if target.name == 'prod-cloud' else 'view' }}" keep it scoped to your project only, not to all models, so Elementary can keep its own (mostly incremental) materializations. [[Quickstart dbt package](https://docs.elementary-data.com/data-tests/dbt/quickstart-package#page-title)] 3. Run the Elementary models From your dbt project: bash dbt deps dbt run --select elementary This will create/materialize the Elementary tables (e.g. ELEMENTARY_TEST_RESULTS, DBT_RUN_RESULTS, etc.) in your Snowflake warehouse under the configured schema. [[Quickstart dbt package](https://docs.elementary-data.com/data-tests/dbt/quickstart-package#page-title)] 4. (Optional) Full refresh of Elementary incremental models If you later change materialization settings or need to rebuild the tables: bash dbt run --select elementary --full-refresh --vars '{"elementary_full_refresh": "true"}' [[OSS FAQ – full refresh](https://docs.elementary-data.com/oss/general/faq#page-title)] After this, running dbt test will start populating those Snowflake tables with test results and artifacts.Valerie Wong
12/23/2025, 8:32 PMkapa.ai
12/23/2025, 8:32 PMkapa.ai
12/23/2025, 8:32 PMfreshness_anomalies and dbt’s native source freshness solve related but different problems and work differently. ### 1. What they monitor - dbt source freshness - Checks if a source is fresh compared to a fixed threshold you define (e.g. “fail if data is older than 6 hours”). - Implemented only for sources, not models. [[Slack – dbt source freshness only for sources](https://elementary-community.slack.com/archives/C02CTC89LAX/p1696346623801349?thread_ts=1696346623.801349&cid=C02CTC89LAX)] - Elementary freshness_anomalies - Monitors the time between updates over time and looks for anomalies in that pattern (statistical / z‑score based). [[Freshness anomalies intro](https://docs.elementary-data.com/data-tests/introduction#page-title); [freshness_anomalies behavior](https://docs.elementary-data.com/data-tests/anomaly-detection-tests/freshness-anomalies)] - Works on both sources and models. [[Slack – works on sources and models](https://elementary-community.slack.com/archives/C02CTC89LAX/p1696346623801349?thread_ts=1696346623.801349&cid=C02CTC89LAX)] ### 2. Threshold vs anomaly‑based - dbt source freshness - You define explicit SLAs (e.g. warn_after, error_after); dbt simply checks if the latest timestamp exceeds those limits. - This is a threshold test. - freshness_anomalies - Does not use a user‑defined threshold like “older than 38 hours”. - Splits data into time buckets (daily by default), computes the max gap without updates per bucket, then compares recent buckets to historical ones; it fails only if the recent freshness is anomalous vs history. [[freshness_anomalies behavior](https://docs.elementary-data.com/data-tests/anomaly-detection-tests/freshness-anomalies)] - Elementary explicitly notes that if you want a single “older than X hours/days” rule, that’s not what freshness_anomalies does; you’d use dbt source freshness or another threshold‑style test instead. [[Slack – threshold vs anomaly](https://elementary-community.slack.com/archives/C02CTC89LAX/p1683294589948059?thread_ts=1683294589.948059&cid=C02CTC89LAX); [Slack – stale data & generic test](https://elementary-community.slack.com/archives/C02CTC89LAX/p1684401442974139?thread_ts=1684401442.974139&cid=C02CTC89LAX)] ### 3. Behavior on rarely updated / already‑stale tables - If a table hasn’t been updated for a long time and that’s already its “normal” state: - freshness_anomalies may pass, because all buckets look similarly stale, so there’s no anomaly. [[Slack – month‑old data still passing](https://elementary-community.slack.com/archives/C02CTC89LAX/p1684401442974139?thread_ts=1684401442.974139&cid=C02CTC89LAX); [Slack – table not updated in a month](https://elementary-community.slack.com/archives/C02CTC89LAX/p1686242948441989?thread_ts=1686242948.441989&cid=C02CTC89LAX)] - dbt source freshness would still fail if the latest timestamp is older than your configured threshold. ### 4. How results appear in Elementary - freshness_anomalies is a dbt test, so it runs with dbt test and its results appear in the Elementary report/UI as an anomaly test. [[Add tests – freshness anomalies](https://docs.elementary-data.com/data-tests/add-elementary-tests#page-title)] - `dbt source freshness`: - Runs via dbt source freshness. - Historically, it did not show up as a regular test in the Elementary report because it doesn’t return a standard dbt test result object; Elementary has used it mainly for alerts, with an open issue to surface it like other tests. [[Slack – not revealed in report](https://elementary-community.slack.com/archives/C02CTC89LAX/p1682416734937579?thread_ts=1682416734.937579&cid=C02CTC89LAX); [Slack – implementation difference](https://elementary-community.slack.com/archives/C02CTC89LAX/p1682503992494309?thread_ts=1682503992.494309&cid=C02CTC89LAX)] ### 5. When to use which - Use dbt source freshness when: - You have a clear SLA like “error if older than 6 hours / 1 day”. - You want deterministic pass/fail based on that SLA. - Use elementary.freshness_anomalies when: - You want Elementary to learn the normal update pattern and alert only when it deviates (e.g. daily table stops updating, or weekly table suddenly lags much longer than usual). - You want the same freshness logic on models as well as sources. [[Freshness anomalies description](https://docs.elementary-data.com/data-tests/introduction#page-title); [Slack – works on models and sources](https://elementary-community.slack.com/archives/C02CTC89LAX/p1696346623801349?thread_ts=1696346623.801349&cid=C02CTC89LAX)] If you describe your update pattern and whether you prefer strict SLAs or anomaly‑based alerts, I can suggest a concrete config (or combination) that fits.