A metric that returns a number nobody expected is harder than an error: nothing fails. The Semantic Layer is deterministic, though, and every number comes from SQL you can read. Three steps narrow the problem down, and a short list of causes covers most cases.

Copy and paste

1. Read the definition the Semantic Layer is using, from the manifest, not from your editor:

dbt parse
python -c "import json; m=json.load(open('target/semantic_manifest.json')); \
print(json.dumps([x for x in m['metrics'] if x['name']=='revenue_ytd'], indent=2))"

2. Get the SQL and run it yourself:

dbt sl query --metrics revenue_ytd --group-by metric_time__month --compile   # dbt platform
mf query --metrics revenue_ytd --group-by metric_time__month --explain       # dbt Core

3. Reconcile against the model with a query you write by hand:

select date_trunc('month', order_date) as month, sum(amount) as revenue
from analytics.orders
group by 1
order by 1;

If step 3 agrees with what people expect and step 2 doesn’t, the definition is the problem. If both agree with each other but not with expectations, the expectation or the data is.

Causes that turned up in testing

Causes outside the Semantic Layer

      - name: order_id
        data_tests:
          - unique
          - not_null
        entity:
          type: primary
          name: order

Keep the answer

When you find the cause, add a test that would have caught it: a unique test on the key, a saved query with a known value checked in CI, or a description on the metric that states its date and filters. The next person who doubts the number will read the definition before rerunning step 3.

The causes were reproduced with dbt Core 1.12, dbt v2 2.0.9 and MetricFlow 0.213 on DuckDB.

References