no-discarded-tagged-outcome
Handle a returned tagged outcome instead of discarding it.
Why
A tagged return union makes possible outcomes visible in the type contract. Discarding the value bypasses the caller's opportunity to handle its alternatives, including a declared failure.
Fix
Use or forward the returned outcome. Handle its variants with match and a typed exhaustive fallback such as assert_never; preserve payloads and side effects. Do not delete the operation or hide the result behind a dummy assignment.
Examples
from typing import Annotated, Literalfrom pydantic import BaseModel, Field
class Success[T](BaseModel): kind: Literal["success"] = "success" value: T
class Error[E](BaseModel): kind: Literal["error"] = "error" error: E
class Denied(BaseModel): code: Literal["denied"] = "denied" name: str
type Result[T, E] = Annotated[Success[T] | Error[E], Field(discriminator="kind")]
def save(name: str, allowed: bool) -> Result[str, Denied]: return ( Success[str](value=name) if allowed else Error[Denied](error=Denied(name=name)) )
persist = savepersist("record-7", False)from typing import Annotated, Literalfrom pydantic import BaseModel, Field
class Success[T](BaseModel): kind: Literal["success"] = "success" value: T
class Error[E](BaseModel): kind: Literal["error"] = "error" error: E
class Denied(BaseModel): code: Literal["denied"] = "denied" name: str
type Result[T, E] = Annotated[Success[T] | Error[E], Field(discriminator="kind")]
def save(name: str, allowed: bool) -> Result[str, Denied]: return ( Success[str](value=name) if allowed else Error[Denied](error=Denied(name=name)) )
persist = save
def run() -> Result[str, Denied]: return persist("record-7", False)from typing import Annotated, Literalfrom pydantic import BaseModel, Field
class Success[T](BaseModel): kind: Literal["success"] = "success" value: T
class Error[E](BaseModel): kind: Literal["error"] = "error" error: E
class Denied(BaseModel): code: Literal["denied"] = "denied" name: str
type Result[T, E] = Annotated[Success[T] | Error[E], Field(discriminator="kind")]
def save(name: str, allowed: bool) -> Result[str, Denied]: return ( Success[str](value=name) if allowed else Error[Denied](error=Denied(name=name)) )
save("record-7", False)from typing import Annotated, Literalfrom pydantic import BaseModel, Field
class Success[T](BaseModel): kind: Literal["success"] = "success" value: T
class Error[E](BaseModel): kind: Literal["error"] = "error" error: E
class Denied(BaseModel): code: Literal["denied"] = "denied" name: str
type Result[T, E] = Annotated[Success[T] | Error[E], Field(discriminator="kind")]
def save(name: str, allowed: bool) -> Result[str, Denied]: return ( Success[str](value=name) if allowed else Error[Denied](error=Denied(name=name)) )
def run(name: str, allowed: bool) -> Result[str, Denied]: return save(name, allowed)from typing import Literalfrom pydantic import BaseModel
class Accepted(BaseModel): kind: Literal["accepted"] value: str
class Rejected(BaseModel): kind: Literal["rejected"] reason: str
type Outcome = Accepted | Rejected
def check(value: str) -> Outcome: return Accepted(kind="accepted", value=value)
check("value")from typing import Literalfrom pydantic import BaseModel
class Accepted(BaseModel): kind: Literal["accepted"] value: str
class Rejected(BaseModel): kind: Literal["rejected"] reason: str
type Outcome = Accepted | Rejected
def check(value: str) -> Outcome: return Accepted(kind="accepted", value=value)
def run() -> Outcome: return check("value")