cc-changelog
CONTRIBUTOR TOOL - Track CC changelog, extract new versions since last check, analyze impact on plugin (breaking changes, opportunities, deprecations). Run…
Narrow bare rescue in Elixir so real errors like KeyError and typos propagate instead of being swallowed. Use to audit rescues and refactor error handling.
$ npx -y skills add oliver-kriska/claude-elixir-phoenix --skill narrow-bare-rescue --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/narrow-bare-rescueContext preview
The summary Claude sees to decide when to auto-load this skill.
Narrow bare rescue in Elixir so real errors like KeyError and typos propagate instead of being swallowed. Use to audit rescues and refactor error handling.
name: narrow-bare-rescue description: "Narrow bare rescue in Elixir so real errors like KeyError and typos propagate instead of being swallowed. Use to audit rescues and refactor error handling." effort: medium user-invocable: true argument-hint: "[file_path | directory | --all]" paths: - "**/*.ex" - "**/*.exs"
Turn `rescue _ -> fallback` into `rescue _ in [ExceptionType1, ExceptionType2] -> fallback` so programmer bugs propagate while known failure modes stay handled.
Bare rescues (`rescue _ ->`, `rescue e ->` — any form without an `in` clause) swallow **every** exception, including `UndefinedFunctionError` from typos, `KeyError` from misspelled map keys, and `CompileError` from bad HEEx templates. The symptom isn't a stack trace — it's a silent `{:error, :generic}` or a `nil` fallback. Bugs that should surface in tests or error reporters become quiet degradations.
The Erlang [Secure Coding Guide](https://www.erlang.org/doc/system/secure_coding.html) makes the same case at the BEAM level — rule **LNG-002** ("Do Not Use `catch`") warns that the legacy catch-all form conflates normal returns, throws, and errors. Bare `rescue` in Elixir is the direct analogue.
1. **Never leave `rescue _ ->` or `rescue e ->` without an `in` clause.** Every rescue must list exact exception types. The Credo check enforces this after cleanup lands. 2. **Cover every exception the code path can actually raise.** Narrowing that drops a real exception is a behavioral regression — trace each call in the body before committing. 3. **Never include programmer-bug exceptions in the list.** `UndefinedFunctionError`, `CompileError`, `BadFunctionError`, and `BadArityError` must propagate. 4. **Use `reraise e, __STACKTRACE__`, never `reraise e, []`.** Preserve the original stack trace so Oban retry metadata and error reporters show the real origin. 5. **Run `mix compile --warnings-as-errors` before committing.** Typos in exception module names only surface at compile time — the code looks fine until it loads.
# Before — masks programmer bugs
def parse(body) do
Jason.decode!(body)
rescue
_ -> %{}
end
# After — catches only what can actually fail here
def parse(body) do
Jason.decode!(body)
rescue
_ in [Jason.DecodeError, ArgumentError] -> %{}
endApplies identically to `try … rescue …` and to function-body `def … rescue …`.
The skill operates in three modes depending on scope:
1. **Single file** — `/narrow-bare-rescue path/to/file.ex` 2. **Directory** — `/narrow-bare-rescue lib/my_app/util/` 3. **Whole project** — `/narrow-bare-rescue --all`
Whatever the scope, follow this sequence.
grep -rn "^\s*rescue\s*$" <scope> | head -200
For each hit, read the 3 lines after to classify:
Read the `try` / `def` body and trace what each call can raise. Don't guess from the function name — verify. Consult order:
1. **Check `${CLAUDE_SKILL_DIR}/references/taxonomy.md`** for the work type (JSON, Ecto, Money, HTTP, etc.). Most sites map cleanly to one row. 2. **Grep deps for `defexception`** when a specific library isn't in the taxonomy:
grep -rn "defexception" deps/<libname>/lib/ | head -10
3. **Check `raise` calls in the code path itself** — if the body explicitly raises `RuntimeError`, include it.
Priorities: cover everything the code can actually raise, exclude programmer-bug exceptions (see Iron Law #3), and prefer specific types (`Jason.DecodeError` beats `ArgumentError` if both could apply).
For files with ≥3 rescues sharing a taxonomy, hoist to a module attribute — see `${CLAUDE_SKILL_DIR}/references/patterns.md` for the module-attribute pattern, Oban reraise, ExCmd exit errors, and `is_exception/1` replacements.
After changes in each file (or cluster of files), run:
mix compile --warnings-as-errors mix format <files_changed> mix test <test_files_for_affected_modules>
The compile step catches typos in exception module names — a real risk since you're writing module names from memory.
This skill narrows bare `rescue` clauses. It does not:
category, plus library-specific gotchas (NimbleCSV, Plug, Phoenix LiveView tokenizer)
Oban reraise, ExCmd exit errors, module-attribute hoisting, partitioning large cleanups, the regression-prevention Credo check
— BEAM-level rationale for preferring narrow `try ... catch` / `try ... rescue` over the legacy catch-all form
Docs: phxagents.dev -- install guides per runtime, the runtime compatibility matrix, all 26 Iron Laws, and a browsable skill and agent catalog. Claude Code is great.
Repo: oliver-kriska/claude-elixir-phoenix
CONTRIBUTOR TOOL - Track CC changelog, extract new versions since last check, analyze impact on plugin (breaking changes, opportunities, deprecations). Run…
Run an A/B codex review experiment — holistic codex review vs 3 focused dimension passes (security, ecto, liveview) on the branch diff, classify findings,…
CONTRIBUTOR TOOL - Validate plugin against latest Claude Code documentation. Catches breaking changes, deprecations, discovers new features. Run before…
Guide plugin development workflow — editing skills, agents, hooks, or eval framework in this repo. Use when modifying files in plugins/elixir-phoenix/,…
Generate X/Twitter release promotion posts with ASCII tables and CodeSnap rendering. Use when writing release posts, promotion tweets, plugin announcements, or…
CONTRIBUTOR TOOL - Cut a plugin release: bump plugin.json version, finalize CHANGELOG, update README if needed, gate on make ci, commit, tag vX.Y.Z, and create…