Skip to main content

Troubleshooting

Every failure is recorded. Start from the run, not from your logs.

# All failed runs in the last day
curl "https://api.inbox.kobana.com.br/v1/workflow-runs?status=failed&created_at[gte]=2026-09-08T00:00:00Z" \
--cert ./client.crt --key ./client.key -H "Authorization: Bearer $JWT"

# Everything about one of them
curl "https://api.inbox.kobana.com.br/v1/workflow-runs/$RUN_ID" \
--cert ./client.crt --key ./client.key -H "Authorization: Bearer $JWT"

WorkflowRun.error lists every failed step, one per line, each prefixed with its position (step 2: …), so the run tells you where to look before you open the steps.

"The e-mail was processed but nothing happened in my system"​

Check, in order:

  1. Is there a run at all? GET /v1/workflow-runs?email_id=…. If the list is empty, the agent returned no workflow — the analysis is in Email.agent_metadata, and this is a prompt problem, not an integration problem.
  2. Is there a run with summary.total: 0 and an invalid workflow … error? The agent emitted something that did not validate. The offending value is in definition.
  3. Otherwise, the run exists and its error names the failing step.

Error catalog​

errorWhat happenedWhat to do
invalid workflow at \0.url`: …`The agent's array did not validate. Nothing was sent.Read definition. Usually a missing url, a type other than request, or a reserved header. Fix the prompt.
workflow exceeds 20 stepsThe agent produced more steps than the ceiling.Split the work, or make the prompt summarise into fewer calls.
secret `X` is not defined in this workspaceA ${{secrets.X}} reference has no matching secret. Nothing was sent.GET /v1/secrets and compare. Typo in the prompt, deleted secret, or the secret lives in another workspace — they are never shared.
\`steps.2.response.body.id\` refers to a step that has not run yetA forward reference — a step that comes later. (A reference to a step that failed or was skipped does not fail the step: it is skipped.)Steps only see earlier steps. Reorder, or fix the index.
\`steps.0.response.body.data.id\` could not be resolvedThe path does not exist in that response.Look at response.body on step 0 — the destination's shape is probably not what the prompt assumed.
`steps.0.response.body.id` resolved to nullThe path exists but is null.Same as above: the destination returned no id, usually because the call did not do what you think it did.
expected status 201, got 422The destination rejected the payload.response.body on that step has its reason. Payload problem — fix the prompt or the mapping.
expected status 200, got 401The credential was refused.Rotate with PUT /v1/secrets (same key). Check last_used_at moved — if it did not, the step never reached that secret.
timeout after 30000msThe destination did not answer in 30s.Destination problem. The request may still have been processed — treat the operation as unknown, not as failed.
expected status 2xx, got 302The destination answered a redirect.Redirects are never followed — a 302 to a private host would bypass every check — so a 3xx is just a non-matching status. Point the step at the final URL.
url not allowed: private_ipThe resolved URL points at a private, loopback, link-local or metadata address.Expected for internal hosts: workflows only reach the public internet. Expose an endpoint, or use a webhook and call yourself back.
url not allowed: http_not_allowedPlain http:// outside development.Use https://.
url not allowed: dns_failureThe hostname does not resolve.Typo, or a name that only resolves inside your network.
unsupported step type \delay``A stored step has a type this version cannot execute.Only request exists today.

Reading the stored request​

Each step keeps the request as sent — after placeholder substitution, with secret values replaced by [REDACTED]:

{
"position": 0,
"status": "failed",
"request": {
"url": "https://erp.example.com/payables",
"headers": { "Authorization": "Bearer [REDACTED]", "content-type": "application/json" },
"body": "{\"supplier\":\"ACME\",\"amount\":1250.5}"
},
"response": {
"status": 422,
"expected_status": 201,
"body": "{\"error\":\"supplier not found\"}"
},
"error": "expected status 201, got 422"
}

Two fields answer two different questions:

  • request on the step — what we actually sent. Use it against destination-side problems.
  • definition on the run — what the agent wrote, placeholders unresolved. Use it against prompt problems.

[REDACTED] is not a masking of a value we could show you: the plaintext was never written. Do not try to recover a credential from a run.

Statuses that are not failures​

SituationMeaning
Step skippedIt references a step that did not succeed (failed or skipped) — error says depends on step N, which did not succeed. It was never sent.
Run running for a long timeThe run was interrupted mid-flight (worker restart). It is not retried, because some steps may already have reached your systems. Re-running is a human decision — POST /v1/emails/{id}/reprocess starts the whole pipeline again, agent call included.
Run pendingQueued, not started yet. Normal for a few seconds.
summary.succeeded: 2 with status: failedStep 1 failed, step 2 depended on it and was skipped, steps 0 and 3 are independent and succeeded. Those two did happen in your systems.

That last row is the one to internalise: a failed run does not mean nothing happened. Partial effects are real, and there is no rollback — independent steps run even when another one fails, and a step only depends on what it references. Design the chain so each step is one you would accept happening without the others it does not reference (create, then attach, then notify — not notify, then create).

Watching it continuously​

Subscribe a webhook to workflow.run.failed instead of polling:

{
"event": { "slug": "workflow.run.failed" },
"data": {
"workflow_run_id": "9c8b7a65-…",
"summary": { "total": 3, "succeeded": 1, "error": 2 },
"failed_step": 1,
"failed_steps": [1],
"error": "expected status 201, got 422",
"email": { "id": "…", "subject": "…" },
"agent_run": { "id": "…", "llm_model": "…" }
}
}

The email and agent_run snapshots ride along, so an alert can carry the subject line and the model without a follow-up call.