Error Handling Guide
Strategies for handling errors in Smithers workflows.Basic Error Handling
Use theonError callback:
Copy
Ask AI
<Claude
onFinished={(result) => console.log("Success:", result.output)}
onError={(error) => console.error("Failed:", error.message)}
>
Perform the task.
</Claude>
Retry with State
Implement retry logic with signals:Copy
Ask AI
import { useQueryValue } from "smithers-orchestrator/reactive-sqlite";
function RetryWorkflow() {
const { db, reactiveDb } = useSmithers();
const attempts = useQueryValue<number>(
reactiveDb,
"SELECT CAST(value AS INTEGER) FROM state WHERE key = 'attempts'"
) ?? 0;
const lastError = useQueryValue<string>(
reactiveDb,
"SELECT value FROM state WHERE key = 'lastError'"
);
return (
<SmithersProvider db={db} executionId={executionId} maxIterations={5}>
<If condition={attempts < 3}>
<Claude
onFinished={() => db.state.set("lastError", null)}
onError={(err) => {
db.state.set("lastError", err.message);
db.state.set("attempts", attempts + 1);
}}
>
<If condition={lastError !== null}>
<>Previous attempt failed: {lastError}</>
</If>
Attempt the task (attempt {attempts + 1}/3).
</Claude>
</If>
<If condition={attempts >= 3}>
<Stop reason={`Failed after 3 attempts: ${lastError}`} />
</If>
</SmithersProvider>
);
}
Orchestration-Level Errors
Handle errors at the orchestration level:Copy
Ask AI
<SmithersProvider
db={db}
executionId={executionId}
globalTimeout={3600000}
onError={async (error) => {
// Log to database
await db.vcs.addReport({
type: "error",
severity: "critical",
title: "Workflow Failed",
content: error.message,
});
// Send notification
await sendAlert(`Workflow failed: ${error.message}`);
}}
>
<WorkflowContent />
</SmithersProvider>
Stop Conditions
Use stop conditions to catch issues early:Copy
Ask AI
<SmithersProvider
db={db}
executionId={executionId}
stopConditions={[
{ type: "total_tokens", value: 50000 },
{ type: "report_severity", value: "critical" },
{
type: "custom",
fn: (result) => result.output.includes("FATAL"),
message: "Fatal error detected",
},
]}
onStopRequested={() => {
console.log("Workflow stopped by condition");
}}
>
Database Logging
Log errors to the database for debugging:Copy
Ask AI
<Claude
onError={async (error) => {
// Log the failure
await db.vcs.addReport({
type: "error",
severity: "warning",
title: "Agent Failed",
content: error.message,
metadata: {
phase: phase,
attempts: attempts,
timestamp: new Date().toISOString(),
},
});
// Store learning for future
await db.memories.addLearning(
`error-${Date.now()}`,
`Encountered error: ${error.message}`,
"error handler"
);
}}
>
Graceful Degradation
Fall back to simpler approaches:Copy
Ask AI
import { useQueryValue } from "smithers-orchestrator/reactive-sqlite";
function ResilientWorkflow() {
const { db, reactiveDb } = useSmithers();
const approach = useQueryValue<string>(
reactiveDb,
"SELECT value FROM state WHERE key = 'approach'"
) ?? "full";
const setApproach = (newApproach: string) => {
db.state.set("approach", newApproach);
};
return (
<SmithersProvider db={db} executionId={executionId} maxIterations={5}>
<If condition={approach === "full"}>
<Claude
model="opus"
maxTurns={20}
onFinished={() => setApproach("done")}
onError={() => setApproach("simple")}
>
Comprehensive analysis with full toolset.
</Claude>
</If>
<If condition={approach === "simple"}>
<Claude
model="sonnet"
maxTurns={5}
allowedTools={["Read"]}
onFinished={() => setApproach("done")}
onError={() => setApproach("manual")}
>
Simplified analysis, read-only.
</Claude>
</If>
<If condition={approach === "manual"}>
<Human
message="Automated analysis failed"
onApprove={() => setApproach("done")}
>
Both automated approaches failed.
Please review manually.
</Human>
</If>
</SmithersProvider>
);
}
Validation Errors
Handle schema validation failures:Copy
Ask AI
<Claude
schema={StrictSchema}
maxRetries={2}
onFinished={(result) => {
if (!result.structured) {
console.warn("No structured output");
return;
}
// Use structured output
}}
onError={(error) => {
if (error.message.includes("validation")) {
console.error("Schema validation failed after retries");
// Fall back to unstructured output
}
}}
>
Timeout Handling
Handle timeouts explicitly:Copy
Ask AI
<Claude
timeout={60000} // 1 minute
onError={(error) => {
if (error.message.includes("timeout")) {
console.log("Agent timed out, trying shorter task");
setApproach("shorter");
}
}}
>
Complete Error Handling Pattern
Copy
Ask AI
import { useQueryValue } from "smithers-orchestrator/reactive-sqlite";
function RobustWorkflow() {
const { db, reactiveDb } = useSmithers();
const phase = useQueryValue<string>(
reactiveDb,
"SELECT value FROM state WHERE key = 'phase'"
) ?? "start";
const attempts = useQueryValue<number>(
reactiveDb,
"SELECT CAST(value AS INTEGER) FROM state WHERE key = 'attempts'"
) ?? 0;
const errorsJson = useQueryValue<string>(
reactiveDb,
"SELECT value FROM state WHERE key = 'errors'"
);
const errors: string[] = errorsJson ? JSON.parse(errorsJson) : [];
return (
<SmithersProvider
db={db}
executionId={executionId}
globalTimeout={3600000}
maxIterations={10}
stopConditions={[
{ type: "total_tokens", value: 100000 },
]}
onError={async (error) => {
await db.vcs.addReport({
type: "error",
severity: "critical",
title: "Workflow Error",
content: error.message,
});
}}
onMaxIterations={() => {
console.error("Max iterations reached");
}}
>
<If condition={phase === "start" && attempts < 3}>
<Claude
onFinished={() => db.state.set("phase", "done")}
onError={(error) => {
const newErrors = [...errors, error.message];
db.state.set("errors", JSON.stringify(newErrors));
db.state.set("attempts", attempts + 1);
if (attempts >= 2) {
db.state.set("phase", "fallback");
}
}}
>
Primary task.
<If condition={errors.length > 0}>
<>Previous errors: {errors.join(", ")}</>
</If>
</Claude>
</If>
<If condition={phase === "fallback"}>
<Human
message="Automated task failed"
onApprove={() => db.state.set("phase", "done")}
onReject={() => db.state.set("phase", "cancelled")}
>
Failed {attempts} times.
Errors: {errors.join("; ")}
</Human>
</If>
<If condition={phase === "cancelled"}>
<Stop reason="Cancelled after failures" />
</If>
</SmithersProvider>
);
}