“Works on my machine” stopped being a joke when CI became the only place where your environment is clean. Four causes account for nearly every red CI with identical code.
You changed nothing and CI broke. A dependency published a new version and your
requirements with no upper bound accepted it. The classic: a library that starts
requiring a version of another that dropped a transitive dependency.
sqlmodel>=0.0.45,<0.0.48 # the ceiling is what prevents the silent break
Without a ceiling, the next release is a scheduled date for your CI to fail.
Different lint version, different Python, or a package installed only on your machine. CI installs from scratch — which is exactly where it shows you what your environment was hiding.
Reproduce before blaming CI: run the same command, in the same interpreter, in a clean environment. If it passes clean, the difference is your environment.
The test passes because the file exists on your disk — and the file is in .gitignore
(or was never added). In CI it does not exist and the test fails for a reason that looks
invented.
One-command check: list the files the test reads and confirm every one is under version control.
A dependency or build cache can mask the failure: the job passes using an old artifact. If the same commit fails without the cache and passes with it, the problem is the cache — and it will come back.
See the Ship Your MCP Server skill See all skills
Want this wired into your project? Guided setup from R$ 1.500, with the first cycle run together.
Sent when I publish, together with the free skill used here. No spam, one-click unsubscribe.