Skip to content
nim-error-handling logo

Nim Error Handling

nim-error-handling

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

planetis-m/skills0installs59stars

SKILL.md

Full skill instructions

Nim Error Handling

Use this skill to decide where code should raise, catch, translate, or return structured failure data.

Rules

Choose the Failure Channel

  • Raise exceptions for invalid input, semantic/​validation failure, and operational/​runtime failure (I/​O, OS, network).
  • Return bool for probe-style queries where failure means “not found / condition not met” and no value payload is needed.
  • Return Option[T] when the absent value is a value type with no natural sentinel and the caller benefits from composable operations like map or flatMap.
  • For scanning/​parsing helpers, return consumed length as int (0 = no match) and write the parsed value via a var out-parameter.
  • Use structured result objects only at the orchestrator/​batch boundary, where exceptions are converted into per-item outputs.
  • Do not pass ad-hoc (ok, kind, message) step-result objects through straight-line internal flows.

Place Boundaries

  • Internal step procs should raise (do not catch in the same layer).
  • Catch only to recover, translate at a boundary, record failure, or clean up.
  • Keep the success path straight-line between boundaries.
  • Do not wrap each raising call in its own local try/​except.
  • Validate at boundaries where data enters from outside the typed flow: files, network, user input, config text, FFI, and public API inputs.
  • Add fallback logic only when the caller has a useful recovery path. If failure only leaves stale or unusable state, report the boundary error plainly.

Choose Exception Types

  • Catch CatchableError as the recoverable catch-all. Do not catch bare Exception.
  • Use specific existing exception types such as ValueError, IOError, and OSError when callers should distinguish them.
  • Add a custom exception type only when callers need a narrower semantic type for distinct handling.
  • Custom exception types must derive from CatchableError (recoverable) or Defect (programming bugs).
  • Inherit from a more specific existing base like ValueError or IOError when the semantic fit is clear.
  • Deriving directly from CatchableError or Defect is fine when no intermediate base matches.

Make Contracts Explicit

  • Add explicit raises contracts on exported procs only when the exception surface is stable and narrow.
  • Do not annotate every internal helper by default.
  • Use .raises: [] for a proc that must not raise.
  • Use .raises: [X] when one specific exception type is part of the contract.
  • Treat raises as a compiler-checked contract, not documentation prose.

Translate and Inspect Errors

  • Translate low-level errors only at module/​subsystem boundaries.
  • Add local context and preserve the underlying reason in the new message (include the original exception message).
  • If the handler only needs the message text, use getCurrentExceptionMsg().
  • If the handler needs the exception object or fields, use except X as e or getCurrentException().

Cleanup

  • Use try/​finally for cleanup.

Workflow

  1. Decide whether failure is expected. If it is an expected miss, return bool, Option, or a parse-length value. Do not throw.
  2. Mark the boundaries. Step procs raise. Parse helpers may catch once. Module boundaries may translate. Orchestrators may record per-item failure.
  3. Pick the exception type. Start with an existing type. Add a subtype only if callers need distinct handling.
  4. Write the contract. Add raises on exported procs when the exception surface is narrow and stable. Keep it accurate.
  5. Verify the shape. Compile the code. Run the repo tests. If you wrote raises, ensure the compiler accepts the contract.

Minimal Pattern

import std/[options]

proc findConfig*(paths: seq[string]): Option[string] =
  for p in paths:
    if fileExists(p):
      return some(p)
  none(string)

proc loadConfig*(path: string): Config =
  if path.len == 0:
    raise newException(ValueError, "config path is empty")
  try:
    result = parseConfig(readFile(path))
  except IOError:
    raise newException(IOError, "cannot read config: " & getCurrentExceptionMsg())

Common Mistakes

MistakeWhy it is wrong
Catching in every layerHides the real boundary and makes failure flow harder to follow
Throwing for an expected missTurns normal control flow into exception flow
Passing ok/​kind/​message objects between internal stepsReimplements exception propagation with more boilerplate
Catching bare ExceptionAlso catches Defect, which is not recoverable application flow
Adding a custom exception type with no distinct handlingAdds type noise without changing the contract
Using try/​except for cleanupCleanup belongs in finally
Adding fallback logic without a useful recovery pathPreserves stale or unusable state and obscures the real boundary failure

References

  • references/​batch_preview_boundary.md — Batch boundary that records per-item failures

Changelog

  • 2026-04-09: Initial skill.
  • 2026-04-11: Added raises contracts, exception base-class rules, expected-miss return channels.
  • 2026-04-14: Refined failure channel guidance.
  • 2026-04-17: Removed retry advice.
  • 2026-05-08: Added boundary validation guidance.

More skills from planetis-m

nim-api-design logo
planetis-m/skills

nim-api-design

Design clear public Nim APIs for libraries and modules, including exported types, constructors, lookup functions, error contracts, and container-style interfaces. Use when creating or reviewing a Nim library API, designing an exported module surface, or deciding how callers should construct, acce...

59 0
View
ocr-tool logo
planetis-m/ocr-tool

ocr-tool

Extract raw text from PDF files with OCR, including full-document extraction, selected page ranges, and reuse of cached pages. Use when a user asks to OCR a PDF, extract text from a scanned PDF, or read selected PDF pages.

1 0
View
nim-c-wrappers logo
planetis-m/skills

nim-c-wrappers

Turn low-level C FFI bindings into an idiomatic Nim API, with safer types, cleaner module boundaries, resource management, callbacks, enums, bitflags, and exception-based error handling. Use when building a high-level Nim wrapper around a C library or improving the usability of existing raw bindi...

59 0
View
nim-style-guide logo
planetis-m/skills

nim-style-guide

Write clear, consistent Nim code in a simple stdlib-aligned style, covering imports, naming, proc vs func vs template choices, local variables, constructors, formatting, and control flow. Use when writing new Nim code or reviewing a Nim module for readability, consistency, and low-noise style dec...

59 0
View
rag-tool logo
planetis-m/rag-tool

rag-tool

Store and search text or markdown as semantic chunks in a reusable local vector store. Use when a user wants to ingest documents or retrieve relevant passages from previously stored material.

1 0
View
study-assistant logo
planetis-m/study-assistant

study-assistant

Study assistant workflow for turning provided study material into exam-focused deliverables such as verbatim transcriptions, study notes, lecture-style explanations, ELI5 explanations, flashcards, Mermaid mind maps, quizzes, and essay questions.

5 0
View
nim-code-organization logo
planetis-m/skills

nim-code-organization

Organize Nim code into clear modules and multi-step workflows, with explicit state, top-level helper procs, narrow exports, and easy-to-follow orchestration. Use when refactoring a large Nim file, splitting logic across modules, designing parser-style stateful code, or cleaning up nested helpers ...

59 0
View
nim-ownership-hooks logo
planetis-m/skills

nim-ownership-hooks

Implement and review Nim ARC/ORC ownership hooks for types that manually manage resources, including move-only, deep-copy, refcounted, and copy-on-write patterns. Use when a Nim type owns pointers, buffers, file descriptors, or custom heap memory and you need correct `=destroy`, `=copy`, `=dup`, ...

59 0
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View