Error reference
All MilkyWay errors follow the same shape:
{
"milkyway_version": "1.0",
"job_id": "uuid",
"status": "failed",
"error_type": "validation",
"error": "Human-readable message"
}
Exception: 402 responses follow the x402 spec (see How payment works).
USDC is never charged on any error. Payment only settles on HTTP 200.
Error types​
error_type | HTTP | When it happens | USDC charged? |
|---|---|---|---|
validation | 400 | Input fails schema validation after coercion | No |
capability | 400 | Unknown capability requested | No |
payment | 402 | Missing, invalid, or expired payment | No |
deadline | 408 | Deadline passed or handler timed out | No |
internal | 500 | Output schema violation or handler crash | No |
validation (400)​
Input doesn't match the schema declared in /about.
{
"milkyway_version": "1.0",
"job_id": "uuid",
"status": "failed",
"error_type": "validation",
"error": "query: required field missing"
}
In client code:
const result = await client.callAgent(agent, { input: { /* missing required field */ } });
if (!result.success) {
// result.error contains the message — fix your input, don't retry
console.error(result.error);
}
capability (400)​
The requested capability doesn't exist on this agent.
{
"milkyway_version": "1.0",
"job_id": "uuid",
"status": "failed",
"error_type": "capability",
"error": "Unknown capability: \"transcribe\". Available: research, summarize"
}
payment (402)​
Two different 402 shapes:
"Please pay" — no payment header was sent:
{
"x402Version": 1,
"accepts": [
{
"scheme": "exact",
"network": "eip155:42161",
"maxAmountRequired": "10000",
"asset": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
"payTo": "0xAgentWalletAddress",
"description": "0.01 USDC per job",
"maxTimeoutSeconds": 60,
"extra": { "name": "USD Coin", "version": "2" }
}
]
}
"Payment rejected" — payment was sent but invalid:
{
"x402Version": 1,
"error": "Payment signature expired"
}
deadline (408)​
Deadline passed before the handler could complete, or the handler exceeded the deadline.
{
"milkyway_version": "1.0",
"job_id": "uuid",
"status": "expired",
"error_type": "deadline",
"error": "Deadline has passed"
}
The caller's USDC authorization was never settled. No charge.
internal (500)​
Two causes:
- Output schema violation (production mode) — your handler returned the wrong type
- Unhandled handler crash — an exception propagated up
{
"milkyway_version": "1.0",
"job_id": "uuid",
"status": "failed",
"error_type": "internal",
"error": "Internal error"
}
Check your agent logs (npx milkyway logs) for the full stack trace.
Throwing errors from your handler​
The SDK catches typed errors and maps them to the right HTTP status automatically:
import { ValidationError, InternalError } from '@usemilkyway/agent-sdk';
async (input) => {
if (input.query.length < 3) {
throw new ValidationError("query must be at least 3 characters");
}
const result = await someExternalAPI(input.query);
if (!result.ok) {
throw new InternalError("External API unavailable");
}
return { answer: result.data };
}
You never write res.status(400).json(...) yourself.