| name | find-bugs |
| description | Review newly written charm code for common charm bugs before finishing a BUILD task |
Find Bugs
A bug-hunting pass over charm code you just wrote. Focused on the mistakes
that recur across charms — not a general code review. Run this alongside
security-review before declaring a BUILD task done.
How to use
- Identify the files you added or modified in this task.
- Walk each check below against those files only (not the whole charm).
- Report findings in the structured format at the end. Fix HIGH issues
before finishing; note MEDIUM and LOW.
- Do not re-report things
charm_validate or ruff already caught —
focus on semantics, not style.
Severity
- HIGH — charm will misbehave at runtime (missing status update,
wrong hook observed, data loss). Fix before finishing.
- MEDIUM — degraded behaviour or brittle logic. Note for the user.
- LOW — minor correctness concerns worth flagging.
Checks
1. Status handling
Every charm must end each hook in a defined status. The common bug is a
code path that returns without updating self.unit.status or
self.app.status.
Checklist:
2. Event observation
3. Pebble layer merging (K8s charms)
4. Relation data
5. Secrets handling
6. Storage
7. Update-status
8. Actions
9. Upgrade and refresh
10. Integration with COS
11. Defensive patterns that are actually bugs
except Exception: pass in a hook handler — silently swallows hook
failures and leaves the status stale.
try: self.container.push(...) except ChangeError: pass — hides
Pebble failures; the user sees "active" while the workload is
misconfigured.
- Catching
ops.framework.UncaughtException — if you're catching the
framework's own signal, you're working around a bug rather than fixing it.
12. Async and concurrency
- Charms are single-threaded per hook. If you use
asyncio, you are
probably wrong — ops already handles the event loop.
- Do not
threading.Thread for background work inside a hook. The hook
must complete within ~30 seconds; threads leak between hooks.
Output format
[find-bugs] <N> HIGH, <M> MEDIUM, <K> LOW
HIGH: src/charm.py:87 — missing status update on config-changed error path
Evidence: the `except ValueError` branch returns without setting status,
so the unit stays in the prior status (probably Active) even though
config is invalid.
Fix: set BlockedStatus("invalid config: ...") before returning.
MEDIUM: src/charm.py:142 — relation data written without leadership check
Evidence: self.relation.data[self.app]["count"] = str(n)
Fix: guard with `if self.unit.is_leader():`.
If you find nothing:
[find-bugs] no findings
When to skip
- RESEARCH or DEBUG tasks.
- Edits under 10 lines where no new control flow was introduced.
- Files that are purely tests (run the tests instead — the test output
is a better review).
Otherwise, run it. These bugs are the ones that reach the user as
"charm just went into Blocked and I don't know why".