Skills.

“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.

1. An unpinned dependency

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.

2. The environment is not the same

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.

3. A file that is not versioned

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.

4. A cache that lies

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.

A diagnosis order that works

  1. Read the exact annotationCI tells you file and line. Go there before theorising.
  2. Compare versionsInterpreter and dependencies in CI vs yours. The difference is usually there.
  3. Run clean locallyNew environment, no cache, same version. Reproduced? It is the code. Not reproduced? It is the environment.

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.

← all skills

Get the next article

Sent when I publish, together with the free skill used here. No spam, one-click unsubscribe.

Payment processed by Stripe — no card data touches this server. Instant delivery once confirmed. Prices in BRL (Brazilian real) — you are charged in BRL. Terms, delivery and refund.