Skip to content

fix: error when invalidating a nonexistent environment - #5878

Open
NishchayMahor wants to merge 3 commits into
SQLMesh:mainfrom
NishchayMahor:fix/invalidate-nonexistent-environment
Open

fix: error when invalidating a nonexistent environment#5878
NishchayMahor wants to merge 3 commits into
SQLMesh:mainfrom
NishchayMahor:fix/invalidate-nonexistent-environment

Conversation

@NishchayMahor

Copy link
Copy Markdown

What

sqlmesh invalidate ENVIRONMENT reports success even when the environment doesn't exist:

$ sqlmesh invalidate doesnotexist
Environment 'doesnotexist' invalidated.

That's misleading — a mistyped environment name looks like it worked. This checks that the environment exists first and raises a clear error with a nonzero exit code otherwise:

$ sqlmesh invalidate doesnotexist
Error: Environment 'doesnotexist' does not exist.
$ echo $?
1

How

Context.invalidate_environment now looks the environment up via state_sync.get_environment before invalidating, and raises SQLMeshError when it's absent (the CLI's @error_handler maps that to exit code 1). The message and exception match the existing "environment not found" patterns already used elsewhere in context.py.

Testing

  • New unit test test_invalidate_environment_nonexistent_raises (fails without the fix).
  • Existing test_invalidate_environment_{sync,no_sync} and the test_invalidating_environment integration test still pass.
  • Verified end to end on a fresh sqlmesh init duckdb project: nonexistent env → Error: Environment '...' does not exist. with exit code 1.

Fixes #5621

@StuffbyYuki
StuffbyYuki requested a review from gjesse July 15, 2026 15:29

@gjesse gjesse left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks good to me, clean and well tested. my only minor suggestion is to change the error wording to f"Environment '{environment} was not found" instead of "does not exist." as that's the wording convention we use elsewhere.

@NishchayMahor

Copy link
Copy Markdown
Author

good call, done. switched it to Environment '{name}' was not found. to match the convention. thanks for the review!

@StuffbyYuki

Copy link
Copy Markdown
Collaborator

@gjesse Following up on another review since the author made the changes

@NishchayMahor

Copy link
Copy Markdown
Author

Friendly ping — this has @gjesse's approval and the wording change he asked for is in. Anything else needed from me, or is it just waiting on a merge?

@StuffbyYuki

Copy link
Copy Markdown
Collaborator

Oh I didn't notice he approved it. I just kicked off the ci tests and once they're good I'll merge it

sqlmesh invalidate ENVIRONMENT reported success even when the environment
did not exist, so a mistyped name looked like it worked. Check the
environment exists first and raise a clear error (nonzero exit) otherwise.

Fixes SQLMesh#5621

Signed-off-by: Nishchay Mahor <nishchaymahor@gmail.com>
Signed-off-by: Nishchay Mahor <nishchaymahor@gmail.com>
@NishchayMahor
NishchayMahor force-pushed the fix/invalidate-nonexistent-environment branch from 6289aec to 23bc02e Compare August 16, 2026 21:23
@NishchayMahor

Copy link
Copy Markdown
Author

Thanks for kicking off CI @StuffbyYuki — sorry, that red run was my branch being stale rather than anything in the change. Rebased onto latest main and it should be clean now.

What happened: the only failure was a single mypy error, and it wasn't in a file this PR touches —

sqlmesh/core/console.py:2923: error: Item "None" of "InteractiveShell | None" has no attribute "user_ns"  [union-attr]

That was fixed on main on 2026-08-03 by "fix(mypy) - add ipython None check in accordance with new IPython 9.16". This branch was opened before that and had drifted 36 commits behind, so CI checked out the pre-fix console.py and make py-style failed across all six Python/Windows jobs. My diff is still just the two files (core/context.py, tests/core/test_context.py, +16 lines) — unchanged by the rebase.

Verified locally after rebasing: mypy sqlmesh/core/console.pySuccess: no issues found.

One thing I could not verify locally: the sushi_context fixture doesn't initialize in my environment (get_custom_materialization_type raises for custom_full_with_custom_kind), and it fails identically on a clean origin/main checkout — 16 failed / 58 passed either way — so that's my setup, not the branch. I'm relying on CI for the actual test run.

Note that main's own CI has been red on every run I can see going back to 2026-08-06, so there may be a separate unrelated failure waiting. Happy to look into that separately if it'd help.

@NishchayMahor

Copy link
Copy Markdown
Author

Correcting myself — I got the last comment wrong twice, sorry.

The remaining failure was mine, not stale-branch fallout. test_deploy_prod_forward_only failed with assert 3 == 2, and it passes on clean main and fails on my branch. I should have checked that before telling you it would be clean.

The cause: I put the existence check unconditionally in GenericContext.invalidate_environment, but GithubController.try_invalidate_pr_environment also calls it — after a prod deploy, to mark the PR environment for GC. That environment may never have been created (a forward-only deploy being exactly such a case), so the method depends on a missing environment being a silent no-op. My change turned that into a raised SQLMeshError, which surfaced as a third "Prod Environment Synced" check run. The method being named try_invalidate_... was a hint I walked straight past.

Fixed in fac00c88 by gating it behind must_exist=False, with the two user-facing entry points — the invalidate CLI command and the %invalidate magic — opting in. The behavior this PR is about is unchanged; library callers keep the lenient path. Added a regression test pinning the no-op default so this can't come back.

Verified locally: test_deploy_prod_forward_only passes, tests/integrations/github/ 85 passed, tests/core/test_context.py 103 passed, mypy clean on all three changed files.

Second correction: I said main's CI had been red since 2026-08-06 and implied it might explain my failure. That was misleading. The runs do show red, but the failing jobs there are engine-tests-docker (spark) and (clickhouse)style-and-cicd-tests passes on main. It had nothing to do with my failure and I shouldn't have raised it.

I'd earlier said the sushi_context fixture wouldn't initialize locally; that was my own incomplete install — I'd missed ./examples/custom_materializations from make install-dev. With that installed the suite runs properly, which is how I found the real bug.

The existence check was applied unconditionally in
GenericContext.invalidate_environment, which broke
GithubController.try_invalidate_pr_environment. That method invalidates
the PR environment after a prod deploy, and the environment may never
have been created — a forward-only deploy being one case — so it relies
on a missing environment being a silent no-op. Raising there turned a
routine cleanup into a failed deploy, which is what
test_deploy_prod_forward_only caught.

Move the check behind must_exist=False and have the two user-facing
entry points, the invalidate CLI command and the %invalidate magic, opt
in. The reported behavior is unchanged; library callers keep the
lenient path. Adds a regression test pinning the no-op default.

Signed-off-by: Nishchay Mahor <nishchaymahor@gmail.com>
@NishchayMahor
NishchayMahor force-pushed the fix/invalidate-nonexistent-environment branch from fac00c8 to f082aea Compare August 17, 2026 07:37
@NishchayMahor

Copy link
Copy Markdown
Author

That last red check was a missing DCO sign-off on my must_exist commit, not a test failure — amended with --signoff. The tree is unchanged (0712b968), so the rest of the run that just went green still applies.

@NishchayMahor

Copy link
Copy Markdown
Author

Heads up that the push reset the workflow approval — both runs are sitting at action_required, so they'll need one more "Approve and run" when you get a moment.

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.

sqlmesh invalidate allows invalidating nonexistent environments

3 participants