diff --git a/core/wren/src/wren/context.py b/core/wren/src/wren/context.py index 7ad8a2917c..666bb63681 100644 --- a/core/wren/src/wren/context.py +++ b/core/wren/src/wren/context.py @@ -1155,7 +1155,18 @@ def validate_project(project_path: Path) -> list[ValidationError]: ) continue rel_name = rel.get("name", f"relationships[{i}]") - ref_models = rel.get("models") or [] + ref_models = rel.get("models") + if ref_models is None: + ref_models = [] + if not isinstance(ref_models, list): + errors.append( + ValidationError( + "error", + f"relationships > {rel_name}", + f"'models' must be a list, got {type(ref_models).__name__}", + ) + ) + ref_models = [] for m in ref_models: if m not in all_entity_names: errors.append( diff --git a/core/wren/tests/unit/test_context.py b/core/wren/tests/unit/test_context.py index 3bef80df56..488b01c508 100644 --- a/core/wren/tests/unit/test_context.py +++ b/core/wren/tests/unit/test_context.py @@ -1628,3 +1628,18 @@ def test_validate_manifest_invalid_datasource(): manifest = {**_SEM_BASE_MANIFEST, "views": [_VALID_VIEW]} result = validate_manifest(_b64(manifest), "not-a-datasource") assert len(result["errors"]) == 1 + + +def test_validate_relationship_models_must_be_list(tmp_path): + """Non-list relationship models is a structural error, not iterated as chars.""" + _make_valid_project(tmp_path) + (tmp_path / "relationships.yml").write_text( + "relationships:\n" + " - name: bad\n" + " models: orders\n" + " condition: a.id = b.id\n" + " join_type: MANY_TO_ONE\n" + ) + errors = validate_project(tmp_path) + hard = [e for e in errors if e.level == "error"] + assert any("must be a list" in e.message for e in hard)