agentleFS
dbtinoy-dbtinoy-/lexigram-framework-skills/using-result-and-error-codes/SKILL.md

using-result-and-error-codes

Skill1 starsChanged 3 months agoMITView on GitHub

Use when handling domain errors, adding exception classes, or working with the LEX_ERR_* error code system in Lexigram

The file

We split this skill into the rules it gives an agent

3 rules. About 0 are common, 2 are distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈2

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

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

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

    Every exception has a _code attribute: LEX_ERR_<DOMAIN>_<NNN>.

    line 83
  2. Distinctive:

    No exception defined in two places

    line 116
  3. Distinctive:

    Every package needs a base exception class

    line 118

≈ “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

Using Result and Error Codes

Overview

Lexigram uses a two-track error strategy: Result[T, E] for expected domain failures, exceptions for unexpected infrastructure failures. Every exception carries a LEX_ERR_<DOMAIN>_<NNN> code.

Two-Track Strategy

Use Result[T, E]Use Exceptions
User not found, validation failedDatabase connection lost
Payment declined, permission deniedNetwork timeout, OOM
Business rule violationMissing API key
LLM content filter triggeredSerialization bug

Result API

from lexigram.result import Result, Ok, Err
from lexigram.result.utils import as_result, collect, partition

result = await service.find_user("123")

result.is_ok() / result.is_err()
result.unwrap() / result.unwrap_err()   # only after is_ok/ is_err check
result.unwrap_or(default) / result.unwrap_or_else(fn)

# Sync transforms
result.map_sync(lambda u: u.email)
result.and_then_sync(validate_user)

# Async transforms
await result.map(load_profile)
await result.and_then(create_order)

# Exhaustive match
msg = result.match(
    ok=lambda u: f"Found {u.name}",
    err=lambda e: f"Error: {e}",
)

# Utils
result.expect("Should have found user")
result.to_optional()
result.inspect(lambda u: ...)

# Chaining helpers (lexigram.result.utils)
@as_result(ValueError, KeyError)
async def parse(data: str) -> int: ...

results = [Ok(1), Err("bad"), Ok(2)]
all_ok = collect(results)          # Result[list[int], str]
oks, errs = partition(results)     # ([1, 2], ["bad"])

Prohibited Patterns

# ❌ Never unwrap() without checking
user = result.unwrap()

# ❌ Never wrap infrastructure errors in Result
try:
    data = await db.query(sql)
except DatabaseError as e:
    return Err(e)   # Let exceptions propagate

# ❌ Never use Result for infallible operations
def add(a: int, b: int) -> Result[int, Never]:
    return Ok(a + b)

# ❌ Never use Any as error type
async def execute() -> Result[SkillResult, Any]: ...

Error Code System

Every exception has a _code attribute: LEX_ERR_<DOMAIN>_<NNN>.

Hundreds of registered codes across 40+ packages — see REF_ERROR_CODES.md.

Hierarchy

lexigram-contracts                    Extension Package
──────────────────                    ────────────────
LEX_ERR_AI_001 AIError               LEX_ERR_LLM_002 LLMError(AIError)
                                     LEX_ERR_LLM_003 LLMAuthenticationError(LLMError)
                                     
LEX_ERR_AGT_001 AgentError           LEX_ERR_AGT_004 AgentConfigurationError(AgentError)
                                     LEX_ERR_AGT_005 AgentExecutionError(AgentError)

Creating New Exceptions

# Pick an UNUSED code in the domain's range (see docs/reference/REF_ERROR_CODES.md
# for taken codes). Codes are unique across the whole monorepo — e.g.
# LEX_ERR_CACHE_012 (LockAcquisitionError) and _013 (CacheSerializationError)
# are already taken.

class CacheCustomError(CacheError):
    _code = "LEX_ERR_CACHE_020"  # placeholder: use the actual next free number
    """Custom cache error."""

Rules

  • Base domain exceptions in lexigram-contracts, leaf exceptions in extension packages
  • One definition per code across the entire monorepo
  • No exception defined in two places
  • Extensions extend contracts base (class MyError(ContractsBaseError))
  • Every package needs a base exception class

Domain Tags (68 domains)

Common tags: ADMIN (31), AGT (11), AUTH (28), CACHE (15), DB (11), DI (11), DOM (9), EVT (23), LLM (26), MCP (8), RAG (14), SEC (11), SQL (38), WF (22).

Common Mistakes

  • Defining the same error code in two packages
  • Using Result for infrastructure failures (let them propagate)
  • Calling unwrap() without is_ok() check
  • Returning Result from __init__ or lifecycle hooks (boot, shutdown)
  • Using Any as the error type parameter

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.