<@U088WCP3B4P> hey! I have this config defined on ...
# ask-elementary-ai
j
@kapa.ai hey! I have this config defined on a dbt model
Copy code
data_tests:
      # Monitor status distribution per employer
      - elementary.dimension_anomalies:
          arguments:
            dimensions:
              - status
              - employer_id
            time_bucket:
              period: month
              count: 1
            training_period:
              period: month
              count: 7
            detection_period:
              period: month
              count: 1
            exclude_detection_period_from_training: true
what I was hoping it would do is create buckets on the combination of
employer_id
and
status
and the time grouping however when I run the test and then check the elementary tables for my table, it only lists
employer_id
as a dimension
Copy code
select distinct dimension 
from elementary.data_monitoring_metrics 
where full_table_name = 'my_table';

select distinct result_row::jsonb ->> 'dimension' 
from elementary.test_result_rows
where result_row::jsonb ->> 'full_table_name' = 'my_table'
can you only define one dimension per test?
k
You can define multiple dimensions in a single
dimension_anomalies
test, but the behavior is important to understand: when you list multiple dimensions, Elementary monitors the combination of those dimensions together, not each one separately. So with your config:
Copy code
dimensions:
  - status
  - employer_id
Elementary will group by the combination
(status, employer_id)
— e.g.,
"active; employer_123"
— and monitor row counts for each unique pair. [dimensions config] This is confirmed by Elementary support: > "When configured in this way the test is checking the combination of those 2 dimensions together and not separately." [Slack discussion] The fact that you're only seeing
employer_id
in your query results is unexpected given this behavior — it may be worth checking whether the test ran correctly or if there's a data issue. But the design intent is that both dimensions should appear as a combined dimension value. If you want to monitor each dimension independently, you should define two separate tests:
Copy code
data_tests:
  - elementary.dimension_anomalies:
      arguments:
        dimensions:
          - status
        time_bucket:
          period: month
          count: 1
        training_period:
          period: month
          count: 7
        detection_period:
          period: month
          count: 1
  - elementary.dimension_anomalies:
      arguments:
        dimensions:
          - employer_id
        time_bucket:
          period: month
          count: 1
        training_period:
          period: month
          count: 7
        detection_period:
          period: month
          count: 1
[Slack discussion] So to directly answer your question: no, you're not limited to one dimension per test — but multiple dimensions in one test produce a joint grouping, not independent monitoring per dimension. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.
j
@kapa.ai
The fact that you're only seeing
employer_id
in your query results is unexpected given this behavior — it may be worth checking whether the test ran correctly or if there's a data issue
how should i confirm/troubleshoot this?
k
Here are the steps to troubleshoot why you're only seeing
employer_id
as a dimension instead of the combined
(status, employer_id)
value: 1. Check if metrics are actually being collected Query
data_monitoring_metrics
to see what's being stored for your table:
Copy code
SELECT
  bucket_end,
  dimension,
  dimension_value,
  metric_value
FROM elementary.data_monitoring_metrics
WHERE full_table_name = 'my_table'
ORDER BY bucket_end DESC;
This will show you exactly what dimension combinations are being recorded and whether there are gaps in the data. [Anomaly Troubleshooting] 2. Check the anomaly score calculations
Copy code
SELECT
  metric_name,
  latest_metric_value,
  training_avg,
  training_stddev,
  anomaly_score,
  is_anomaly
FROM elementary.metrics_anomaly_score
WHERE full_table_name = 'my_table'
ORDER BY bucket_end DESC;
This will confirm whether anomaly detection is running correctly and on the right dimension values. [Anomaly Troubleshooting] 3. Check the test results table
Copy code
SELECT *
FROM elementary.elementary_test_results
WHERE test_short_name = 'dimension_anomalies'
ORDER BY detected_at DESC
LIMIT 10;
Look at the
test_sub_type
column — it should show
dimension
, not
generic
. If it shows
generic
, that indicates the test configuration may not be picked up correctly (this is a known issue reported by community members). [Slack thread] 4. Try a force backfill If metrics seem stale or incomplete, re-run the test with:
Copy code
dbt test --select your_model --vars '{"force_metrics_backfill": true}'
This forces Elementary to recalculate and re-store metrics from scratch. [Slack thread] 5. Check the dbt logs Review your
dbt/dbt.log
file for any compilation errors or warnings related to the
dimension_anomalies
test. Compilation errors can silently prevent metrics from being written to
data_monitoring_metrics
. [Anomaly Troubleshooting] Also note: there is a known bug where
dimension_anomalies
tests don't always pick up configuration from the model level (e.g.,
timestamp_column
). If you're setting any config at the model level rather than directly in the test arguments, try moving it into the test arguments explicitly. [Slack thread] 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.
j
@kapa.ai when I run query 1 the only
dimension
value is
employer_id
k
That's a useful data point. Based on what the knowledge sources tell us about how
dimension_anomalies
works with multiple dimensions, the expected behavior is that the
dimension
column in
data_monitoring_metrics
should reflect the combined dimension expression (e.g.,
"status; employer_id"
), not just one of the two columns. Seeing only
employer_id
suggests one of the following: 1. A previous test run with only
employer_id
as a dimension is still in the table
If you previously ran the test with only
employer_id
configured, those older rows would still be in
data_monitoring_metrics
. Check whether the rows showing
employer_id
are from recent runs or older ones:
Copy code
SELECT
  bucket_end,
  updated_at,
  dimension,
  dimension_value,
  metric_value
FROM elementary.data_monitoring_metrics
WHERE full_table_name = 'my_table'
ORDER BY updated_at DESC;
2. The current test configuration isn't being picked up correctly Try running with a force backfill to ensure the latest config is applied:
Copy code
dbt test --select your_model --vars '{"force_metrics_backfill": true}'
Then re-run query 1 and check if the
dimension
column now shows the combined value. [Anomaly Troubleshooting] 3. Check the test results to confirm the test is running as
dimension
subtype
Copy code
SELECT *
FROM elementary.elementary_test_results
WHERE test_short_name = 'dimension_anomalies'
ORDER BY detected_at DESC
LIMIT 5;
The
test_sub_type
should be
dimension
. If it's
generic
, the test configuration may not be correctly recognized. [Slack thread] The knowledge sources don't explicitly document a case where only one of two configured dimensions appears — so this is likely either a stale data issue or a configuration not being applied correctly. The force backfill + checking
updated_at
timestamps should help you narrow it down. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.
j
@kapa.ai explain what this test is doing end explain which months i would expect to see for training and detection periods
Copy code
data_tests:
      # Monitor status distribution per employer
      - elementary.dimension_anomalies:
          arguments:
            dimensions:
              - status
              - employer_id
              - elementary_timestamp_override
            time_bucket:
              period: month
              count: 1
            training_period:
              period: month
              count: 7
            detection_period:
              period: month
              count: 1
            exclude_detection_period_from_training: true
k
This test is a
dimension_anomalies
anomaly-detection test that: • Groups rows by the combination of: ◦
status
◦
employer_id
◦
elementary_timestamp_override
(multiple dimensions are treated as a joint key, e.g.
"active; employer_123; 2026-03-01"
). [dimensions config; dimension_anomalies behavior] • Builds monthly time buckets (
time_bucket: period: month, count: 1
), so each bucket is one full calendar month. [time_bucket] • Counts rows per (status, employer_id, elementary_timestamp_override, month) and monitors how those counts change over time. [dimension_anomalies intro] • Uses: ◦
training_period: 7 months
◦
detection_period: 1 month
◦
exclude_detection_period_from_training: true
so the detection month is not used to compute the expected range. [training_period; exclude_detection_period_from_training] Which months are training vs detection? Elementary always works on complete time buckets. With
time_bucket: month
and
detection_period: 1 month
, the *detection period is the last fully completed month*; incomplete “current” month is not used. [detection_period; Slack explanation] Assume today is somewhere in April 2026 and April is not yet complete: • Detection month (1 month): ◦ Last completed month → March 2026 (bucket
2026‑03‑01
→
2026‑04‑01
). • Training months (7 months), with `exclude_detection_period_from_training: true`: ◦ The 7 full months before March 2026: ▪︎ August 2025 – February 2026 (Aug, Sep, Oct, Nov, Dec 2025; Jan, Feb 2026). So for each
(status, employer_id, elementary_timestamp_override)
combination, the test: 1. Takes the row count in March 2026 (detection bucket). 2. Compares it to the distribution of row counts from Aug 2025–Feb 2026 (training buckets), excluding March from training because of
exclude_detection_period_from_training: true
. [training_period; exclude_detection_period_from_training] If you run the same config later (e.g., in May 2026, once April is complete), the detection month would shift to April 2026, and the 7‑month training window would shift to September 2025 – March 2026, always keeping 7 historical full months and 1 latest full month for detection. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.
j
@kapa.ai that's what I thought but the test_result_rows.row_result json for this test has the following:
Copy code
"training_start": "2025-10-01T00:00:00",
"training_end": null,
k
You’re right to question that — what you’re seeing in
test_result_rows.result_row
is not fully aligned with the conceptual description of training/detection periods, and there are known quirks here. From the knowledge sources: • There is a known issue where
training_end
can be
null
in
test_result_rows.result_row
, even when
is_anomalous = true
. A community member explicitly asked if this is a known bug and how to reliably coalesce
training_end
from other fields, which implies this behavior is not currently well-documented or fully correct. [Slack discussion] • Elementary is actively investigating correctness issues around
exclude_detection_period_from_training
, including cases where the detection bucket appears to fall within the training window despite the flag being set. [Slack investigation] So: • Conceptually, with your config, you should have a 7‑month training window and a 1‑month detection window, with the detection month excluded from training. [training_period; exclude_detection_period_from_training] • But the JSON fields in
test_result_rows
are not always reliable
, and
training_end = null
is a known symptom of that. To understand what’s actually happening in your run, the recommended approach from the docs and community is to ignore
training_end
in
test_result_rows
and instead: 1. Inspect
metrics_anomaly_score
directly:SELECT bucket_start, bucket_end, training_start, training_end, training_set_size, metric_value, is_anomalous FROM elementary.metrics_anomaly_score WHERE full_table_name = 'my_table' ORDER BY bucket_end DESC;This table is the authoritative source for how the training window was applied. [Anomaly troubleshooting] 2. Cross‑check with
data_monitoring_metrics
to see which buckets exist and which one is the latest detection bucket:SELECT bucket_start, bucket_end, dimension, dimension_value, metric_value FROM elementary.data_monitoring_metrics WHERE full_table_name = 'my_table' ORDER BY bucket_end DESC; ``` [[Anomaly troubleshooting](https://docs.elementary-data.com/data-tests/anomaly-detection-tests/Anomaly-troubleshooting-guide#page-title)] Because the knowledge sources explicitly say there are open investigations and bugs around both
exclude_detection_period_from_training
and the training metadata fields, I cannot confidently reconcile your `training_start`/`training_end = null` purely from docs — it’s likely a manifestation of those known issues rather than your config being wrong. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.
j
@kapa.ai my table isn't in metrics_anomaly_score
k
It’s expected to see no rows in
metrics_anomaly_score
when something earlier in the pipeline isn’t satisfied. Based on the knowledge, here’s how to narrow it down for your
dimension_anomalies
test: 1. Confirm metrics are being collected at all You already saw your table in
data_monitoring_metrics
, but run this to be explicit:
Copy code
SELECT
  bucket_end,
  dimension,
  dimension_value,
  metric_name,
  metric_value
FROM elementary.data_monitoring_metrics
WHERE full_table_name = 'my_table'
ORDER BY bucket_end DESC;
If no rows come back,
metrics_anomaly_score
will also be empty. In that case, the test isn’t writing metrics (config / compilation issue). [Metrics table purpose] You’ve said you do see rows there, so move on. 2. Check if there’s “enough data to calculate anomaly” Elementary only creates rows in
metrics_anomaly_score
once there are enough training points (≥ 7). Before that, you’ll see “Not enough data to calculate anomaly score” and
metrics_anomaly_score
stays empty. [Anomaly troubleshooting] Look at the number of distinct buckets for your table:
Copy code
SELECT
  COUNT(DISTINCT bucket_end) AS buckets,
  MIN(bucket_end) AS first_bucket,
  MAX(bucket_end) AS last_bucket
FROM elementary.data_monitoring_metrics
WHERE full_table_name = 'my_table';
If
buckets < 7
, you won’t see anything in
metrics_anomaly_score
yet. 3. Verify the test is recognized as dimension_anomalies If the test is mis‑parsed as a generic test, it may not flow into
metrics_anomaly_score
as expected.
Copy code
SELECT
  test_name,
  test_sub_type,
  detected_at,
  status
FROM elementary.elementary_test_results
WHERE test_short_name = 'dimension_anomalies'
  AND full_table_name = 'my_table'
ORDER BY detected_at DESC
LIMIT 10;
•
test_sub_type
should be
dimension
. • If it’s
generic
, there’s a config recognition issue. [Dimension subtype issue] 4. Force metrics backfill with your current config If you changed the test recently, older metrics may not match the new config and scoring may not have been recomputed. Run:
Copy code
dbt test --select my_table --vars '{"force_metrics_backfill": true}'
Then re‑check:
Copy code
SELECT *
FROM elementary.metrics_anomaly_score
WHERE full_table_name = 'my_table'
ORDER BY bucket_end DESC;
For
dimension_anomalies
, forcing backfill is a recommended step when config changes or results look off. [Force backfill] 5. If still empty: likely a known limitation/bug The knowledge sources mention: • Cases where anomaly tests (especially
dimension_anomalies
) populate
data_monitoring_metrics
but never produce rows in
metrics_anomaly_score
, even though the config looks correct. [Dimension anomalies issues] • Open bugs around
dimension_anomalies
configuration handling and training metadata. [Known bug] So if: •
data_monitoring_metrics
has ≥ 7 buckets for your table, •
elementary_test_results
shows
test_sub_type = 'dimension'
, • you’ve run with
force_metrics_backfill
, and your table still doesn’t appear in
metrics_anomaly_score
, then based on the docs and threads I have, this is most likely hitting one of those known
dimension_anomalies
issues rather than a misconfiguration on your side. In that case, the next step would be to share: • Your exact test YAML, • A sample of
data_monitoring_metrics
for
my_table
, • And the
elementary_test_results
rows for that test in the Elementary Slack so the team can confirm if it’s the known bug or something schema‑specific. The knowledge sources don’t provide a more specific fix beyond the checks above. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.
j
@kapa.ai i see my table in data_monitoring_metrics but not metrics_anomaly_score
k
You’re not alone in seeing this; the knowledge sources describe exactly this pattern for anomaly tests, especially
dimension_anomalies
and some column tests. Here’s what it means and what you can do, based only on what’s documented: 1.
data_monitoring_metrics
is the “raw metrics” store
If your table appears there, it means the anomaly test is running and writing metric points (per bucket / dimension). [Metrics table purpose] 2.
metrics_anomaly_score
is only populated when scoring is possible
Elementary only writes rows there once it can actually compute anomaly scores from the metrics in
data_monitoring_metrics
. If there aren’t enough valid training points (typically fewer than 7), you’ll see “Not enough data to calculate anomaly score” and no rows in
metrics_anomaly_score
. [Anomaly troubleshooting] 3. Some test types don’t always show up in
metrics_anomaly_score
even when metrics exist
The sources explicitly mention that for certain anomaly tests (notably
all_columns_anomalies
, and in several threads
dimension_anomalies
), users see:This is described as different behavior / a limitation rather than a clear misconfiguration. ◦ Results in
elementary_test_results
and
data_monitoring_metrics
◦ But nothing in
metrics_anomaly_score
, even after history has built up. [All columns vs volume] 1. *What you can reliably check now*Since your table is in
data_monitoring_metrics
but not in
metrics_anomaly_score
, the docs suggest these concrete checks:SELECT COUNT(DISTINCT bucket_end) AS buckets, MIN(bucket_end) AS first_bucket, MAX(bucket_end) AS last_bucket FROM elementary.data_monitoring_metrics WHERE full_table_name = 'my_table';If
buckets < 7
,
metrics_anomaly_score
staying empty is expected. [Anomaly troubleshooting]SELECT test_name, test_sub_type, detected_at, status FROM elementary.elementary_test_results WHERE full_table_name = 'my_table' ORDER BY detected_at DESC LIMIT 10;For
dimension_anomalies
,
test_sub_type
should be `dimension`; if it’s
generic
, config recognition issues can prevent proper scoring. [Slack subtype issue]dbt test --select my_table --vars '{"force_metrics_backfill": true}'Then re-check `metrics_anomaly_score`:SELECT * FROM elementary.metrics_anomaly_score WHERE full_table_name = 'my_table' ORDER BY bucket_end DESC;[Force backfill] ◦ Verify how many buckets you actually have (to rule out “not enough data”): ◦ Confirm the test is recognized as an anomaly subtype: ◦ Force recomputation with your current config: If, after: • ≥ 7 buckets in
data_monitoring_metrics
, •
test_sub_type
is correct, • and a
force_metrics_backfill
run, your table still never appears in
metrics_anomaly_score
, the knowledge sources indicate this is likely hitting one of the known limitations/bugs around anomaly scoring (especially for non-volume tests), rather than something you can fix purely via config. In that case, the recommended next step (per the Slack threads) is to share those query outputs in the Elementary Slack so the team can confirm if it matches the known issues. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.
j
@kapa.ai how can i use the elementary schema to produce the following table: • table_name • schema • column • dimension • dimension_value • is anomalous • detection period start • detection period end • training period start • training period end • detected value • training value • anomaly_score
k
You can get very close to that table by joining Elementary’s core anomaly tables. The knowledge sources don’t show a single “one‑stop” view with exactly those columns, but they do document where each piece of information lives and how to query it. Below is a pattern you can adapt. 1. Where each field comes from From the docs and Slack threads: • Per‑bucket anomaly stats (including
anomaly_score
,
training_avg
,
training_stddev
,
training_start
,
training_end
,
is_anomaly
) are in
metrics_anomaly_score
. [Anomaly troubleshooting; Stddev location] • Raw metrics per bucket and dimension are in
data_monitoring_metrics
. [Metrics table] • Per‑test temporary
__anomaly_scores
tables also contain
training_avg
,
training_stddev
,
min_metric_value
,
max_metric_value
,
anomaly_score
, etc., but they’re per‑test and not centralized. [Per‑test scores] •
full_table_name
is stored in these tables as
DATABASE.SCHEMA.TABLE
. [Troubleshooting guide] So the most reusable base is
metrics_anomaly_score
joined to
data_monitoring_metrics
(if you want the original metric row). 2. Example query to build your table This example assumes: • You want one row per bucket per dimension where an anomaly was evaluated. • “Detection period start/end” = the bucket’s
bucket_start
/
bucket_end
. • “Training period start/end” =
training_start
/
training_end
. • “Detected value” = the metric value in the detection bucket. • “Training value” = the training average (
training_avg
). You can derive
schema
and
table_name
by splitting
full_table_name
if needed (syntax will vary by warehouse).
Copy code
SELECT
  -- Split full_table_name into database / schema / table as needed.
  mas.full_table_name,
  -- Example for warehouses that support SPLIT_PART; adjust for yours:
  SPLIT_PART(mas.full_table_name, '.', 2) AS schema_name,
  SPLIT_PART(mas.full_table_name, '.', 3) AS table_name,

  mas.column_name        AS column,
  mas.dimension,
  mas.dimension_value,

  mas.is_anomaly         AS is_anomalous,

  -- Detection period = the bucket being scored
  mas.bucket_start       AS detection_period_start,
  mas.bucket_end         AS detection_period_end,

  -- Training window used for this score
  mas.training_start     AS training_period_start,
  mas.training_end       AS training_period_end,

  -- Detected vs training values
  mas.latest_metric_value AS detected_value,
  mas.training_avg        AS training_value,

  mas.anomaly_score

FROM <elementary_schema>.metrics_anomaly_score AS mas
-- Optional: join back to data_monitoring_metrics if you need extra raw fields
-- LEFT JOIN <elementary_schema>.data_monitoring_metrics dmm
--   ON mas.id = dmm.id

-- Filter to only anomalous points, or drop this to see all scored buckets
WHERE mas.anomaly_score IS NOT NULL
-- AND mas.is_anomaly = TRUE   -- if you only want flagged anomalies

ORDER BY
  mas.full_table_name,
  mas.column_name,
  mas.dimension,
  mas.dimension_value,
  mas.bucket_end DESC;
This uses only fields that the docs explicitly show as present in `metrics_anomaly_score`:
full_table_name
,
column_name
,
dimension
,
dimension_value
,
metric_name
,
latest_metric_value
,
training_avg
,
training_stddev
,
training_start
,
training_end
,
training_set_size
,
anomaly_score
,
is_anomaly
,
bucket_start
,
bucket_end
,
updated_at
. [metrics_anomaly_score model; Stddev query example] 3. Notes / limitations • If your table doesn’t appear in
metrics_anomaly_score
, but does in
data_monitoring_metrics
, it may be because there aren’t enough training points yet (fewer than 7 buckets) or you’re hitting one of the known
dimension_anomalies
quirks where scoring isn’t materialized there. [Anomaly troubleshooting; Behavior differences] • The exact string splitting for
schema
/
table_name
must match your warehouse’s SQL functions; the knowledge sources don’t prescribe a specific pattern, only that
full_table_name
is
DB.SCHEMA.TABLE
. [Troubleshooting guide] Within those constraints, the query above is the documented way to assemble the view you described from the Elementary schema. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.
j
@kapa.ai how to make elementary persist results to my dev schema for local dbt run/test results, rather than the prod schema
k
There are a few complementary things you need to configure to make Elementary write to your dev schema during local runs. 1. Configure the Elementary schema in dbt_project.yml Place the
elementary
config at the top level of
models:
, not nested under your project name:
Copy code
models:
  my_project:
    materialized: "{{ 'table' if target.name == 'prod' else 'view' }}"

  elementary:
    +schema: "elementary"
This means dbt will create Elementary tables in a schema named
<target_schema>_elementary
(e.g.
dev_elementary
when your target schema is
dev
). [Quickstart package] 2. Handle generate_schema_name if you have a custom macro If your project has a custom
generate_schema_name
macro, it may override Elementary's schema config and send tables to the wrong place. You need to explicitly handle the
elementary
package:
Copy code
{% macro generate_schema_name(custom_schema_name, node) -%}
    {% if node.package_name == 'elementary' %}
        {% set schema_name = node.package_name | trim %}
    {% else %}
        {% set schema_name = generate_schema_name_for_env(custom_schema_name, node) %}
    {% endif %}
    {{ schema_name }}
{%- endmacro %}
After updating the macro, re-run
dbt run --select elementary
to recreate the tables in the correct schema. [Slack discussion] 3. Disable hooks in local dev (optional but recommended) To avoid slowing down local runs, you can disable the
on-run-end
hooks that upload artifacts, while still allowing Elementary tests to run:
Copy code
vars:
  disable_run_results: "{{ target.name not in ['prod','staging','dev'] }}"
  disable_tests_results: "{{ target.name not in ['prod','staging','dev'] }}"
  disable_dbt_artifacts_autoupload: "{{ target.name not in ['prod','staging','dev'] }}"
  disable_dbt_invocation_autoupload: "{{ target.name not in ['prod','staging','dev'] }}"
[Dev/prod configuration] 4. Create the Elementary tables in your dev target Once the config is in place, run:
Copy code
dbt run --select elementary --target dev
This creates the Elementary tables in your dev schema. If you skip this step, the hooks will fail with "Unable to insert rows to non-existent table." [BigQuery Slack thread] 5. Update profiles.yml for edr CLI (if you use it) The
edr
CLI does not respect your custom
generate_schema_name
macro — it only reads the schema from the
elementary
profile in
profiles.yml
. Add a top-level
elementary
profile pointing to your dev schema:
Copy code
elementary:
  target: dev
  outputs:
    dev:
      type: <your_warehouse_type>
      schema: dev_elementary   # must match where Elementary tables are actually created
      # ... other connection details
[Slack reference] 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.
j
@kapa.ai i have the config you mention in step 1. but when i run dbt run -s elementary it creates the tables in the dev schema defined in my dbt cloud account (im using dbt cloud cli, not a profiles.yml)
k
The behavior you're seeing — Elementary tables landing in your default dbt Cloud target schema instead of a custom
elementary
schema — is a known issue when a custom
generate_schema_name
macro is involved, and it also affects dbt Cloud CLI users. Here are the things to check: 1. Do you have a custom generate_schema_name macro? This is the most common cause. If your project has a custom
generate_schema_name
macro, it can override the
+schema: elementary
config and send tables to the wrong place. You need to explicitly handle the
elementary
package in that macro:
Copy code
{% macro generate_schema_name(custom_schema_name, node) -%}
    {% if node.package_name == 'elementary' %}
        {% set schema_name = node.package_name | trim %}
    {% else %}
        {% set schema_name = generate_schema_name_for_env(custom_schema_name, node) %}
    {% endif %}
    {{ schema_name }}
{%- endmacro %}
After updating, re-run
dbt run --select elementary
. [Slack discussion] 2. Check the placement of the elementary config in dbt_project.yml The
elementary
block must be at the top level of
models:
, not nested under your project name. A common mistake is nesting it:
Copy code
# ❌ Wrong - nested under your project
models:
  my_project:
    elementary:
      +schema: elementary

# ✅ Correct - top-level sibling of your project
models:
  my_project:
    ...
  elementary:
    +schema: elementary
If it's nested incorrectly, dbt will warn
There are 1 unused configuration paths
and ignore the schema setting. [Slack thread] 3. dbt Cloud CLI and custom schemas The knowledge sources note that in dbt Cloud CI environments, Elementary models can end up in the wrong schema (e.g., the temporary PR schema or the default target schema) on the first run, and only resolve correctly after a production job has run. This is a known issue specific to dbt Cloud. [GitHub issue] The knowledge sources don't contain enough information to give a dbt Cloud CLI-specific workaround beyond the macro fix above. If fixing the
generate_schema_name
macro doesn't resolve it, I'd recommend raising it in the Elementary Slack with your exact
dbt_project.yml
config and macro, as the team has investigated similar dbt Cloud schema resolution issues there. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.
j
Copy code
{% macro generate_schema_name(custom_schema_name, node) -%}
    {%- set default_schema = target.schema -%}

    {%- if custom_schema_name is not none and target.name == 'production' -%}
        {{ custom_schema_name | trim }}
    {%- else -%}
        {{ default_schema }}
    {%- endif -%}
{%- endmacro %}
@kapa.ai
k
With your current macro, here's what happens for Elementary models: • In
production
target
:
custom_schema_name
is
"elementary"
(from your
+schema: elementary
config), so Elementary tables land in a schema literally named
elementary
. ✅ • In any other target (e.g. dev): the
else
branch fires and returns
default_schema
(your dbt Cloud target schema), ignoring
custom_schema_name
entirely
. This is why Elementary tables land in your default dev schema instead of
dev_elementary
or similar. ❌ To fix this so Elementary gets its own schema in dev too, you need to special-case the
elementary
package. Based on the patterns recommended by Elementary support: [Slack discussion]
Copy code
{% macro generate_schema_name(custom_schema_name, node) -%}
    {%- set default_schema = target.schema -%}

    {%- if node.package_name == 'elementary' and custom_schema_name -%}
        {{ default_schema }}_{{ custom_schema_name | trim }}

    {%- elif custom_schema_name is not none and target.name == 'production' -%}
        {{ custom_schema_name | trim }}

    {%- else -%}
        {{ default_schema }}

    {%- endif -%}
{%- endmacro %}
This means: • All targets: Elementary tables go to
<target_schema>_elementary
(e.g.
dev_elementary
in dev,
prod_elementary
in production). • Production, non-Elementary models: still use the literal
custom_schema_name
as before. • Dev, non-Elementary models: still fall back to
default_schema
as before. After updating the macro, re-run:
Copy code
dbt run --select elementary
to recreate the Elementary tables in the correct schema. [Slack discussion] If you'd prefer Elementary to use a fully literal schema name (not prefixed with the target schema), you can return just
custom_schema_name | trim
in the Elementary branch instead. [OSS FAQ] 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.
j
@kapa.ai i'm not actually worried about which schema the tables are created in. i just want to confirm that when i locally run
Copy code
dbt test --select <my_model>
dbt run --select elementary
that the artifacts generated by my local test run is what will get consumed by my local run of the elementary tables
k
Yes, that's exactly how it works. The two commands are designed to be used together in sequence: 1.
dbt test --select <my_model>
— runs your tests and triggers the
elementary.handle_tests_results
on-run-end hook, which writes results into
elementary_test_results
and
data_monitoring_metrics
(for anomaly tests) in whatever schema Elementary is configured to use in your current target. [on-run-end hooks] 2.
dbt run --select elementary
— runs the Elementary dbt models, which read from those same tables (e.g.
data_monitoring_metrics
→
metrics_anomaly_score
) to produce the derived views and aggregations. Since both commands run against the same target/schema, the Elementary models will consume exactly the metrics and results that your local test run just wrote. [dbt artifacts] So yes — as long as both commands run against the same dbt target (which they will by default in dbt Cloud CLI), your local test results are what get consumed by the Elementary models. There's no cross-environment mixing unless you explicitly switch targets between the two commands. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.
j
do i need the
dbt run --select elementary
after every test run or does the end hook consume the artifacts and append records to the elementary tables? @kapa.ai
k
You do not need
dbt run --select elementary
after every test run. The on-run-end hooks handle appending results automatically. Specifically, after each
dbt test
(or
dbt run
/
dbt build
), the hooks fire and write directly to the Elementary tables: •
elementary_test_results
— via the
elementary.handle_tests_results
hook •
dbt_run_results
— via the
elementary.upload_run_results
hook • Metadata tables (
dbt_models
,
dbt_tests
, etc.) — also updated via on-run-end All of this happens without needing to explicitly run
dbt run --select elementary
. [on-run-end hooks; dbt artifacts]
dbt run --select elementary
is only needed in two situations: 1. First-time setup — to create the Elementary tables in your schema. 2. After a minor version upgrade — when there are schema changes to the Elementary tables. [Slack confirmation] For your regular local workflow, just running
dbt test --select <my_model>
is sufficient to populate the Elementary tables with your test results. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.
j
@kapa.ai help me to debug why this table is empty in my dev
Copy code
select *
from <dev_schema>.metrics_anomaly_score
k
Based on the conversation so far, here's a structured debugging approach for why
metrics_anomaly_score
is empty in your dev schema: Step 1: Confirm metrics are being written at all
Copy code
SELECT
  COUNT(DISTINCT bucket_end) AS buckets,
  MIN(bucket_end) AS first_bucket,
  MAX(bucket_end) AS last_bucket,
  full_table_name
FROM <dev_schema>.data_monitoring_metrics
GROUP BY full_table_name
ORDER BY buckets DESC;
• If this is also empty, your anomaly tests aren't writing metrics at all — check that your
dbt test
is actually running anomaly tests and that the on-run-end hooks are firing (look for
Elementary: Uploading test results
in your
dbt.log
). [Anomaly troubleshooting] • If this has rows, continue to Step 2. Step 2: Check if you have enough training points
metrics_anomaly_score
only gets populated once there are at least 7 training data points. If you have fewer than 7 buckets in
data_monitoring_metrics
for a given table, you'll see "Not enough data to calculate anomaly score" and
metrics_anomaly_score
stays empty. [Anomaly troubleshooting] Your test uses
time_bucket: month
, so you'd need at least 7 months of data in
data_monitoring_metrics
before scores appear. Step 3: Confirm the test is recognized as an anomaly subtype
Copy code
SELECT
  test_name,
  test_short_name,
  test_sub_type,
  detected_at,
  status
FROM <dev_schema>.elementary_test_results
ORDER BY detected_at DESC
LIMIT 10;
For
dimension_anomalies
,
test_sub_type
should be
dimension
. If it shows
generic
, the test configuration isn't being picked up correctly, which can prevent scoring. [Slack subtype issue] Step 4: Force a metrics backfill
Copy code
dbt test --select <your_model> --vars '{"force_metrics_backfill": true}'
Then re-check
metrics_anomaly_score
. This forces Elementary to recompute scores from the existing metrics in
data_monitoring_metrics
. [Force backfill] Step 5: Check that hooks are actually firing in dev Make sure none of these vars are set to
true
in your dev environment, as they would prevent results from being written:
Copy code
vars:
  disable_run_results: true
  disable_tests_results: true
  disable_dbt_artifacts_autoupload: true
  disable_dbt_invocation_autoupload: true
Also check your
dbt.log
for the lines
Elementary: Uploading test results
— if they're missing, the hooks didn't run. [Disabled vars] Given your earlier conversation, the most likely culprit is Step 2 — since your test uses monthly buckets and you're running locally in dev, you may simply not have accumulated 7 months of metric history in your dev schema yet. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.
j
@kapa.ai results of first query
Copy code
8,2025-09-01 00:00:00.000000,2026-04-01 00:00:00.000000,<mymodel1>
7,2025-09-01 00:00:00.000000,2026-03-01 00:00:00.000000,<mymodel2>
k
Your results from Step 1 show: •
<mymodel1>
: 8 buckets, spanning Sept 2025 → April 2026 •
<mymodel2>
: 7 buckets, spanning Sept 2025 → March 2026 Both models have ≥ 7 buckets, so the "not enough training data" threshold should be met. [Anomaly troubleshooting] This means the empty
metrics_anomaly_score
is likely not a training data volume issue. Move on to the remaining steps: Next: Step 3 — Check test subtype
Copy code
SELECT
  test_name,
  test_short_name,
  test_sub_type,
  detected_at,
  status
FROM <dev_schema>.elementary_test_results
WHERE full_table_name LIKE '%mymodel1%'
   OR full_table_name LIKE '%mymodel2%'
ORDER BY detected_at DESC
LIMIT 10;
For
dimension_anomalies
,
test_sub_type
must be
dimension
. If it shows
generic
, the test config isn't being recognized correctly and scoring won't happen. [Slack subtype issue] Then: Step 4 — Force backfill
Copy code
dbt test --select <your_model> --vars '{"force_metrics_backfill": true}'
Then re-check
metrics_anomaly_score
. [Force backfill] Share the output of the Step 3 query and I can help narrow it down further. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.
j
@kapa.ai here are the last 3 columns of the second query
Copy code
dimension_anomalies,dimension,2026-04-09 12:10:31.000000,fail
column_anomalies,standard_deviation,2026-04-09 12:09:48.000000,fail
column_anomalies,standard_deviation,2026-04-09 12:09:48.000000,fail
column_anomalies,zero_count,2026-04-09 12:09:48.000000,fail
column_anomalies,sum,2026-04-09 12:09:48.000000,fail
column_anomalies,average,2026-04-09 12:09:48.000000,fail
column_anomalies,min,2026-04-09 12:09:48.000000,pass
column_anomalies,average,2026-04-09 12:09:48.000000,fail
column_anomalies,max,2026-04-09 12:09:48.000000,fail
column_anomalies,max,2026-04-09 12:09:48.000000,fail
k
Good news: the
dimension_anomalies
test is showing
test_sub_type = dimension
(not
generic
), which means the test configuration is being recognized correctly. [Slack subtype issue] So the test is running and recognized, but
metrics_anomaly_score
is still empty. The next step is: Try a force backfill
Copy code
dbt test --select <your_model> --vars '{"force_metrics_backfill": true}'
Then re-check:
Copy code
SELECT *
FROM <dev_schema>.metrics_anomaly_score
WHERE full_table_name LIKE '%mymodel1%'
   OR full_table_name LIKE '%mymodel2%'
ORDER BY bucket_end DESC;
If it's still empty after the force backfill, this aligns with the known pattern documented in the community where
dimension_anomalies
tests populate
data_monitoring_metrics
but do not produce rows in
metrics_anomaly_score
, even when configuration and data volume look correct. [Dimension anomalies issues; Behavior differences] At that point, the knowledge sources don't provide a further self-service fix — the recommended next step would be to share your test YAML, the
data_monitoring_metrics
sample, and the
elementary_test_results
rows with the Elementary Slack team for them to confirm if it's the known bug. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.
j
@kapa.ai table is still completely empty. who do i reach out to?
k
Based on the troubleshooting steps you've completed, you've confirmed: • ✅
data_monitoring_metrics
has ≥ 7 buckets for both models • ✅
test_sub_type = dimension
(config is recognized correctly) • ✅ Force backfill didn't resolve it • ❌
metrics_anomaly_score
remains empty This matches the known pattern documented in the community where
dimension_anomalies
tests populate
data_monitoring_metrics
but never produce rows in
metrics_anomaly_score
. [Dimension anomalies issues; Behavior differences] The best place to get help is the Elementary community Slack — the knowledge sources show that the Elementary team actively responds there and has investigated similar
dimension_anomalies
issues directly with users. When you post, include: • Your exact test YAML • A sample of
data_monitoring_metrics
for your table • The
elementary_test_results
rows for the test • Your Elementary dbt package version (from
packages.yml
) There is also an open GitHub issue tracking related
dimension_anomalies
bugs that you can comment on or react to, which helps the team prioritize: [GitHub issue #1170] 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.
j
@kapa.ai
Elementary community Slack
which channel or user should i report this issue to?
k
The knowledge sources don't explicitly specify which Slack channel or user to contact for reporting issues. However, based on the URLs in the knowledge sources, the community discussions take place in the
#general
or
#support
style channel with ID
C02CTC89LAX
— but I can't confirm the exact channel name from the sources provided. What I can say is that the Elementary team is reachable via their community Slack, and the knowledge sources also mention you can DM the
@elementary.ai
app
for 1-to-1 help. [Slack thread] For the most accurate channel to post in, I'd recommend joining the Elementary community Slack (via elementary-data.com) and checking the channel list there directly. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.