Skip to content

fix(config): stringify pydantic error loc before join#5884

Open
anxkhn wants to merge 1 commit into
SQLMesh:mainfrom
anxkhn:fix/config-error-loc-int-join
Open

fix(config): stringify pydantic error loc before join#5884
anxkhn wants to merge 1 commit into
SQLMesh:mainfrom
anxkhn:fix/config-error-loc-int-join

Conversation

@anxkhn

@anxkhn anxkhn commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Config validation errors located at a list or tuple index crash with an opaque
TypeError instead of the intended readable ConfigError.

_formatted_validation_errors in sqlmesh/utils/pydantic.py builds the field
location by joining pydantic's error loc tuple directly:

loc_str = ".".join(loc) if loc else None

Pydantic's loc mixes str field names with int sequence indices when an error is
inside a list (for example ("items", 0, "x")), and str.join rejects the int:

TypeError: sequence item 1: expected str instance, int found

So any config error that resolves to a list element surfaces as a traceback rather
than the readable message the function exists to produce. A concrete user-facing
path is an invalid model_defaults.pre_statements entry, whose loc is
("model_defaults", "pre_statements", 0, ...).

The fix converts each loc part to str before joining:

loc_str = ".".join(str(p) for p in loc) if loc else None

Nested-list config errors now render, for example,
Invalid field 'model_defaults.pre_statements.0...' as a ConfigError.

This is a regression from #4511, which replaced the earlier single-element
loc[0] access (never affected by int indices) with the ".".join(loc) form.

Test Plan

  • Added tests/utils/test_pydantic.py::test_validation_error_message_with_list_index_location:
    builds a real nested-model ValidationError (loc == ("items", 0, "x")) and
    asserts validation_error_message returns the formatted string instead of
    raising. Verified it fails with the TypeError before the fix and passes after.
  • Updated tests/core/test_config.py::test_load_model_defaults_validation_statements:
    it previously asserted the raw TypeError, which codified the crash. It now
    expects the readable ConfigError (Invalid field 'model_defaults.pre_statements.0...').
    Also verified this fails before the fix and passes after.
  • pytest tests/utils/test_pydantic.py tests/core/test_config.py -m "not slow and not docker":
    76 passed.
  • make style (ruff check + ruff format + mypy) clean on the changed files.

Checklist

  • I have run make style and fixed any issues
  • I have added tests for my changes (if applicable)
  • All existing tests pass (make fast-test)
  • My commits are signed off (git commit -s) per the DCO

Config validation errors located at a list or tuple index crashed with
'TypeError: sequence item N: expected str instance, int found' because
pydantic's error 'loc' mixes str field names with int sequence indices
while _formatted_validation_errors joined them directly. Convert each
loc part to str before joining so nested-list config errors (for example
an invalid model_defaults.pre_statements entry) render the readable
ConfigError instead of raising.

Update test_load_model_defaults_validation_statements, which previously
asserted the raw TypeError, to expect the readable ConfigError.

Regression from SQLMesh#4511.

Signed-off-by: Anas Khan <83116240+anxkhn@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant