Skip to content

Commit ebd3c67

Browse files
Improve error message for unknown fields in semantic_model config
When a user adds an unknown field (e.g. description) inside the semantic_model: config object, replace the opaque JSON Schema error "is not valid under any of the given schemas" with a clear message naming the offending field and listing the valid ones. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent eee9587 commit ebd3c67

File tree

3 files changed

+74
-0
lines changed

3 files changed

+74
-0
lines changed

core/dbt/contracts/graph/unparsed.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,19 @@ class UnparsedSemanticModelConfig(dbtClassMixin):
551551
group: Optional[str] = None
552552
config: Optional[UnparsedSemanticResourceConfig] = None
553553

554+
@classmethod
555+
@override
556+
def validate(cls, data: Any) -> None:
557+
if isinstance(data, dict):
558+
allowed = set(cls.__dataclass_fields__.keys())
559+
extra = set(data.keys()) - allowed
560+
if extra:
561+
raise ValidationError(
562+
f"Unknown field(s) in semantic_model config: {', '.join(sorted(extra))}. "
563+
f"Valid fields are: {', '.join(sorted(allowed))}."
564+
)
565+
super().validate(data)
566+
554567

555568
@dataclass
556569
class UnparsedModelUpdate(UnparsedNodeUpdate):
@@ -570,6 +583,18 @@ class UnparsedModelUpdate(UnparsedNodeUpdate):
570583
metrics: Optional[List[UnparsedMetricV2]] = None
571584
derived_semantics: Optional[UnparsedDerivedSemantics] = None
572585

586+
@classmethod
587+
@override
588+
def validate(cls, data: Any) -> None:
589+
# Validate the semantic_model sub-object before the full JSON Schema runs so
590+
# that unknown fields produce a clear error instead of the opaque JSON Schema
591+
# message "is not valid under any of the given schemas".
592+
if isinstance(data, dict):
593+
sm = data.get("semantic_model")
594+
if isinstance(sm, dict):
595+
UnparsedSemanticModelConfig.validate(sm)
596+
super().validate(data)
597+
573598
def __post_init__(self) -> None:
574599
if self.latest_version:
575600
version_values = [version.v for version in self.versions]

tests/functional/semantic_models/fixtures.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,3 +1102,29 @@
11021102
type: categorical
11031103
expr: id
11041104
"""
1105+
1106+
# Reproduces: error when description (or other unknown field) is placed inside
1107+
# the semantic_model: config object.
1108+
customer_yaml_semantic_model_with_description = """
1109+
models:
1110+
- name: fct_revenue
1111+
description: This model provides a detailed view of purchase transactions.
1112+
semantic_model:
1113+
enabled: true
1114+
name: purchases
1115+
description: purchases semantic model
1116+
agg_time_dimension: ds
1117+
columns:
1118+
- name: id
1119+
entity:
1120+
name: id_entity
1121+
type: primary
1122+
dimension:
1123+
name: id_dim
1124+
type: categorical
1125+
- name: second_col
1126+
granularity: day
1127+
dimension:
1128+
name: ds
1129+
type: time
1130+
"""

tests/functional/semantic_models/test_semantic_model_v2_parsing.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from tests.functional.semantic_models.fixtures import (
1515
base_schema_yml_v2,
1616
base_schema_yml_v2_with_custom_sm_name,
17+
customer_yaml_semantic_model_with_description,
1718
derived_semantics_with_doc_jinja_yml,
1819
derived_semantics_yml,
1920
fct_revenue_sql,
@@ -992,3 +993,25 @@ def test_metrics_use_model_name_as_semantic_model_name(self, project):
992993

993994
# TODO DI-4605: add enforcement and a test for when there are validity params with no column granularity
994995
# TODO DI-4603: add enforcement and a test for a TIME type dimension and a column that has no granularity set
996+
997+
998+
class TestSemanticModelConfigUnknownFieldClearError:
999+
"""Verifies that unknown fields inside semantic_model: config produce a clear error message
1000+
naming the offending field and the valid fields, instead of the opaque JSON Schema error
1001+
'is not valid under any of the given schemas'."""
1002+
1003+
@pytest.fixture(scope="class")
1004+
def models(self):
1005+
return {
1006+
"schema.yml": customer_yaml_semantic_model_with_description,
1007+
"fct_revenue.sql": fct_revenue_sql,
1008+
"metricflow_time_spine.sql": metricflow_time_spine_sql,
1009+
}
1010+
1011+
def test_unknown_field_in_semantic_model_config_gives_clear_error(self, project) -> None:
1012+
runner = dbtTestRunner()
1013+
result = runner.invoke(["parse"])
1014+
assert not result.success
1015+
error_msg = str(result.exception)
1016+
assert "Unknown field(s) in semantic_model config: description" in error_msg
1017+
assert "Valid fields are:" in error_msg

0 commit comments

Comments
 (0)