agentleFS
VyrnexisVyrnexis/nim-agent-template/skills/nim-error-handling/SKILL.md

nim-error-handling

Skill4 starsChanged 3 months agoMITView on GitHub

Design clear Nim error-handling flows; when to raise exceptions vs return `Option`/`bool`, how to enforce non-raising contracts, and where to translate or record failures. Use when reviewing failure behavior, exception boundaries, recovery, or batch processing that needs per-item error reporting.

1 other project uses a version of this, 1 of them edited.

Adopted by

Most recently taken up by

The file

Show its rules and text

We split this skill into the rules it gives an agent

16 rules. About 0 are common, 5 are distinctive, and 11 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈5

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 11

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Use bool with a var parameter only when filling or mutating caller-owned storage is part of the API.

    line 14
  2. Distinctive:

    Read what the current operation promises and how each called API reports failure.

    line 19
  3. Distinctive:

    If a successful call guarantees valid output, do not add another raising nil, size, or range check.

    line 20
  4. Distinctive:

    If a condition breaks no documented promise, remove the raising check and document the valid behavior.

    line 21
  5. Distinctive:

    If an operation requires a stronger guarantee than the API it calls, validate that guarantee in that operation.

    line 23
  6. Very specific:

    Put child exception types before their parents in except branches.

    line 35
  7. Very specific:

    Add a custom exception only when callers handle it differently.

    line 37
  8. Very specific:

    Do not use Defect for recoverable failures.

    line 38
  9. Very specific:

    Use assert for conditions whose failure means a programming bug: preconditions, internal invariants, and state guards, as in assert …

    line 39
  10. Very specific:

    Do not use range conversions for recoverable validation, e.g.

    line 41
  11. Very specific:

    If the handler only needs the message text, use getCurrentExceptionMsg().

    line 46
  12. Very specific:

    If the handler needs exception fields, use except X as e.

    line 47
  13. Very specific:

    Use try/finally for cleanup.

    line 51
  14. Very specific:

    Use {.raises: [].} when a proc must not raise.

    line 52
  15. Distinctive:

    Place the decision: Document valid behavior as success, or report failure in the first operation whose promise is broken.

    line 58
  16. Very specific:

    Enforce non-raising contracts: Add {.raises: [].} only to procs that must not raise.

    line 60

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Nim Error Handling

Rules

Choose the Failure Channel

  • Return bool when success or failure is the whole result.
  • Return Option[T] when success returns a value but absence is expected.
  • Use bool with a var parameter only when filling or mutating caller-owned storage is part of the API.
  • Convert per-item failures into structured outcomes at the batch boundary. Keep intermediate steps exception-based.

Add Only Real Failure Paths

  • Read what the current operation promises and how each called API reports failure.
  • If a successful call guarantees valid output, do not add another raising nil, size, or range check.
  • If a condition breaks no documented promise, remove the raising check and document the valid behavior.
  • Report failure when the result cannot safely satisfy its API or the operation cannot meet its documented promise.
  • If an operation requires a stronger guarantee than the API it calls, validate that guarantee in that operation.

Place Boundaries

  • Let failures propagate through intermediate steps.
  • Catch only where the handler can recover, translate, or record the failure.
  • At a batch boundary, record recoverable per-item failures.

Choose Exception Types

  • For a contract failure caused by caller input or the environment, raise the closest existing CatchableError.
  • Separate except branches when handling differs. Group exception types when handling is identical.
  • Put child exception types before their parents in except branches.
  • Catch CatchableError only when the boundary handles every recoverable error. Do not catch bare Exception.
  • Add a custom exception only when callers handle it differently. Derive it from the closest existing CatchableError subtype.
  • Do not use Defect for recoverable failures; it represents a programming bug and is not caught by CatchableError.
  • Use assert for conditions whose failure means a programming bug: preconditions, internal invariants, and state guards, as in assert s.opened, "next called before open".
  • Do not use range conversions for recoverable validation, e.g. Positive(parseInt(s)); invalid values raise RangeDefect.

Translate and Inspect Errors

  • Translate errors only at module or subsystem boundaries. Add local context and preserve the original reason.
  • If the handler only needs the message text, use getCurrentExceptionMsg().
  • If the handler needs exception fields, use except X as e.

Cleanup and Contracts

  • Use try/finally for cleanup.
  • Use {.raises: [].} when a proc must not raise. Leave raising procs unannotated.

Workflow

  1. Read the contracts. Note what this operation promises, how called APIs report failure, and what they guarantee on success.
  2. Decide whether failure is needed. Name the documented promise that the condition would break. If there is none, remove the check.
  3. Place the decision. Document valid behavior as success, or report failure in the first operation whose promise is broken.
  4. Place catch boundaries. Catch only where the handler can recover, translate, or record the failure.
  5. Enforce non-raising contracts. Add {.raises: [].} only to procs that must not raise.

Common Mistakes

MistakeWhy it is wrong
Parent except before childFirst-match dispatch makes the child handler unreachable.
Catching bare ExceptionAlso catches Defect and can hide programming bugs.
Rechecking guaranteed outputAdds dead branches and can contradict the lower-level API.
Rejecting allowed behaviorSilently narrows the operation's contract.

References

  • references/batch_preview_boundary.md — Per-item batch failures with reporting failures allowed to escape.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.