6.2Recurring issues (playbook)
The essentials in 30 seconds
- Reflex: one symptom = likely causes = one targeted action — diagnose before touching the code.
- Read: the traceback reads bottom-up: the last line names, the top locates.
- Isolate: any gap between local and CI is fixed with venv, pinned requirements and aligned versions.
Nabil thread — the playbook taped next to the screen
Nabil keeps this playbook next to his screen. Verdict after one year: three lines served him most — the non-activated venv behind ModuleNotFoundError, mixed tabs + spaces, and red CI while everything was green locally. For each, he ended up applying the sequence (read the traceback, check the cause, fix) instead of editing at random.
Observed symptom, verified causes, actions in order: the reflex holds in three steps.
Diagnose before rerunning
Most Python blockers are classics: each symptom has typical causes and one targeted action. The table below groups the most frequent situations, from import to deployment.
| Symptom | Likely causes | Actions |
|---|---|---|
| ModuleNotFoundError | wrong interpreter, venv not activated, file in the wrong place | select the right interpreter, activate the venv, check the path |
| IndentationError / TabError | mixed tabs + spaces | convert to 4 spaces, black to normalise |
| NameError | typo, variable out of scope, forgotten import | reread the last line, check scope and imports |
| KeyError on dict | missing key, direct access | .get() with a default + validate input data |
| It worked yesterday (dependencies) | mixed global, drifted versions | venv + pinned requirements, rebuild to prove |
| Red tests after refactor | behaviour changed unintentionally | read THE failing test, fix the code (not the test), rerun |
| Unreachable API in container | localhost host instead of 0.0.0.0 | CMD with --host 0.0.0.0, -p to publish |
| Red CI, green local | different versions, missing test, absent secret | align versions (requirements), reproduce locally, check secrets |
| Slow script on large volumes | Python loops instead of vectorised/generator | profile, vectorise (pandas/NumPy) or yield |
Ready-to-say script — diagnosing without random edits (30 s)
“My symptom: [ModuleNotFoundError / KeyError / red CI / slowness]. I read the traceback bottom-up, identify the playbook's likely cause, apply the targeted action and verify.”
Copy-paste template — safe access + precise error
def taux_ville(ligne: dict) -> float:
ville = ligne.get("ville", "inconnue")
if ville == "inconnue":
raise ValueError("clé 'ville' absente de la ligne")
return float(ligne.get("taux", 0.0))
VSE / small budget
No formal table: one symptom, the playbook's likely cause, the action and the noted owner.
SME Algiers
Fold local realities into diagnosis: installed versions, shared workstations, known Monday peaks.
Remote / hybrid
Add immediate written logs to the actions: at a distance, an unrecorded symptom looks like a working system.
Intercultural
Spell out findings in writing: what seems obvious (which venv, which version) is not obvious to everyone.
48h challenge — apply tomorrow
Spot 1 current symptom (import, KeyError, red CI), apply the playbook line (traceback read + cause verified + targeted action).
- I can link a symptom to its likely causes.
- I read the traceback bottom-up before fixing.
- I can lock in with venv, hints and tests.
Nabil's script raises KeyError on a sales dict. Which reflex does the playbook apply?
The same hassle returning endlessly is not ten incidents: it is a method to fix (venv, tests, hints).