Sume job_failed_terminal: retryable true means reuse the same key

On job_failed_terminal never resubmit the identical payload. If error.retryable is true, re-issue the create with the same idempotency_key; else fix the input.

4 min readSume
All posts

When a Sume MCP job fails, the result carries agent.recovery.code: job_failed_terminal. Do not resubmit the identical payload. If error.retryable is true, re-issue the same create with the same idempotency_key; if it is false, fix the input and ask the user before spending again.

Read the failure from the right tool

A failed job is a terminal state, and jobs_result is for successful jobs: it answers 409 job_not_completed on a failed one. Read the failure with jobs_get, which carries error.public_reason and the retryable flag. The failed job post shows that read; this post is about what to do next.

The decision

The recovery hint reduces the choice to one flag.

What to do after job_failed_terminal on Sume MCP (read 2026-10-05 against the Sume codebase)
error.retryableSame payload?idempotency_keyNext step
trueyes, unchangedthe same keyre-issue the create once, then jobs_wait
falsenoa new key once the input changesfix the input, ask the user, then create
absentnodo not guessread jobs_get public_reason, then ask

A small router

Put this in the harness, so the model never decides it.

def after_failure(job: dict, key: str) -> dict:
    err = job.get('error') or {}
    if err.get('retryable') is True:
        return {'action': 'recreate', 'idempotency_key': key}
    return {
        'action': 'ask_user',
        'reason': err.get('public_reason', 'unknown'),
    }

print(after_failure({'error': {'retryable': True}}, 'k-1'))
print(after_failure({'error': {'public_reason': 'input_rejected'}}, 'k-1'))

Limits

Operations-stopped jobs are a separate case with their own recovery code, and polling them again will not change the answer. A retry is also not a guarantee: if the same failure repeats, stop and report it rather than looping. Tell the user in plain words what failed, what you tried and what it would cost to try again, so the next decision is theirs.

The failure you are avoiding

An agent sees a failed job, concludes it must try again, and builds a fresh request with a new key. If the first job had in fact produced a charge or was still settling, the second create is a second charge. Reusing the key tells Sume the retry is the same intent as the first call. The opposite mistake is resending an identical payload that failed for a reason inside the input, which fails again the same way. The retryable flag exists to separate those two cases.

Checklist before you ship

  • Read error.retryable from jobs_get, not from the wording of the message.
  • Reuse the original idempotency_key only when retryable is true.
  • Cap retries at one per job so a bad payload cannot loop.
  • When retryable is false, change the input and ask the user first.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume