Skip to content
Sarj Code Standards

prefer-outcome-variants

Express nullable success and error state as tagged outcome variants.

Why

An optional error beside success or payload state admits contradictory combinations. Tagged variants expose complete success payloads and explicit failure context to callers.

Fix

Reuse an established Result[T, E] or declare Success | Error variants with a shared Literal discriminator. Require success payloads and the error value in their respective variants; retain typed partial progress when failures need it. Preserve accepted inputs and serialized contracts during migration.

Examples

Before — flagged A nullable error and success flag admit contradictory outcomes
app/models.py
from pydantic import BaseModel
class AudioResult(BaseModel):
passed: bool = False
error: str | None = None
value: bytes | None = None
After — preferred Success and error variants have non-null payloads
app/models.py
from typing import Literal
from pydantic import BaseModel
class RunSuccess(BaseModel):
passed: Literal[True] = True
value: bytes
class RunError(BaseModel):
passed: Literal[False] = False
error: str
type RunResult = RunSuccess | RunError