Error Handling Guide¶
Lambda tool functions are executed in a thread pool inside a try/except block. Unhandled exceptions are caught, serialised, and returned as error responses to the caller.
Automatic Exception Handling¶
Any exception raised from your tool function is automatically converted to an error response:
ValueError→400 Bad Requestwith{"message": "...", "code": 400}- Any other exception →
500 Internal Server Errorwith{"$schema": "urn:ivcap:schema.ai-tool.error.1", "message": "...", "traceback": "..."}
@ivcap_lambda("/divide")
def divide(req: DivideRequest) -> DivideResult:
"""Divide two numbers"""
if req.divisor == 0:
raise ValueError("divisor must not be zero") # → 400
return DivideResult(result=req.dividend / req.divisor)
Reporting Errors via Events¶
For errors that occur inside a named step, report them through the event system so the IVCAP platform can track what went wrong:
from ivcap_service import JobContext
from ivcap_service.events import GenericErrorEvent
import traceback
@ivcap_lambda("/process")
def process(req: ProcessRequest, jobCtxt: JobContext) -> ProcessResult:
"""Process data"""
with jobCtxt.report.step("load", "Loading data") as step:
try:
data = load_data(req.source)
step.finished(f"Loaded {len(data)} records")
except FileNotFoundError as e:
step.error(e) # marks step as failed
raise ValueError(f"Data source not found: {req.source}") from e
with jobCtxt.report.step("process", "Processing") as step:
try:
result = process_data(data)
step.finished("Done")
except Exception as e:
# Report detailed error event
jobCtxt.report.emit(GenericErrorEvent(
error=str(e),
context="process step failed",
stacktrace=traceback.format_exc(),
))
step.error(e)
raise
return ProcessResult(output=result)
Graceful Degradation¶
For optional features, catch specific exceptions and fall back gracefully:
@ivcap_lambda("/enrich")
def enrich(req: EnrichRequest, jobCtxt: JobContext) -> EnrichResult:
"""Enrich data with optional external lookup"""
base_result = compute_base(req)
# Optional enrichment — fail gracefully
enrichment = None
try:
enrichment = call_external_api(req.id)
except Exception as e:
logger.warning(f"Enrichment failed (continuing without): {e}")
return EnrichResult(
data=base_result,
enrichment=enrichment,
)
Input Validation¶
Use Pydantic's built-in validation to reject bad inputs before your function runs:
from pydantic import BaseModel, Field, field_validator
@with_schema("urn:example:schema:resize.request.1")
class ResizeRequest(BaseModel):
artifact_id: str = Field(..., description="Artifact to resize.")
width: int = Field(..., description="Target width in pixels.", ge=1, le=4096)
height: int = Field(..., description="Target height in pixels.", ge=1, le=4096)
format: str = Field("jpeg", description="Output format.")
@field_validator("format")
@classmethod
def format_must_be_valid(cls, v):
if v.lower() not in ("jpeg", "png", "webp"):
raise ValueError("format must be jpeg, png, or webp")
return v.lower()
Pydantic validation errors result in a 422 Unprocessable Entity response from FastAPI, before your function is even called.
HTTP Error Codes Summary¶
| Situation | HTTP Status | Body |
|---|---|---|
| Pydantic validation fails | 422 |
FastAPI validation error |
ValueError raised |
400 |
{"message": "...", "code": 400} |
| Other exception raised | 500 |
{"$schema": "...", "message": "...", "traceback": "..."} |
| Job still running | 204 |
(empty, Location + Retry-Later headers) |
| Job ID not found or expired | 404 |
(plain text message) |
| Job completed successfully | 200 |
(result model JSON) |
Best Practices¶
- Raise
ValueErrorfor user errors — bad input that the user should fix - Raise other exceptions for system errors — unexpected failures the user can't fix
- Use steps to track where failures occur —
step.error(e)marks the step as failed on the platform - Log the exception at
ERRORlevel — before re-raising, so it appears in logs - Don't swallow exceptions silently — at minimum log a warning so failures are visible
See Also¶
- Tool Functions Guide — Try-later semantics and HTTP status codes
- Observability Guide — Progress reporting and event types
- Best Practices — Robust error patterns