can1357/oh-my-pi · warning · HTTPException
retry requires 'delivery_id' or 'issue'
Error message
retry requires 'delivery_id' or 'issue'
What it means
The retry endpoint requires an identifier to act on and raises HTTP 400 'retry requires delivery_id or issue' when the request body contains neither. The endpoint accepts either a stored delivery_id or an issue reference (`owner/repo#N`) to locate the event; an empty or non-string value for both leaves it with no target, so the request is rejected outright.
Source
Thrown at python/robomp/src/server.py:655
status_code=202,
)
# mode == "retry"
if isinstance(delivery_id, str) and delivery_id:
target = delivery_id
elif isinstance(issue_ref, str) and issue_ref:
try:
repo_full, number = parse_issue_ref(issue_ref)
except InvalidIssueRef as exc:
raise HTTPException(400, str(exc)) from exc
if not cfg.allows(repo_full):
raise HTTPException(403, f"{repo_full} not in ROBOMP_REPO_ALLOWLIST")
row = db.latest_event_for_issue(make_issue_key(repo_full, number))
if row is None:
raise HTTPException(404, f"no retryable stored event for {repo_full}#{number}")
target = row.delivery_id
else:
raise HTTPException(400, "retry requires 'delivery_id' or 'issue'")
event = db.get_event(target)
if event is None:
raise HTTPException(404, f"unknown delivery {target}")
if not db.requeue_event(target, from_states=INACTIVE_EVENT_STATES):
raise HTTPException(409, f"delivery {target} is {event.state}; only inactive events can be retried")
pool.wake()
log.info("manual retry", extra={"delivery": target})
return JSONResponse(
{"delivery": target, "state": "queued", "mode": "retry"},
status_code=202,
)
@app.post("/api/cancel")
async def api_cancel(
request: Request,
payload: dict[str, Any] = Body(...),
x_robomp_token: str | None = Header(None, alias="X-Robomp-Replay-Token"),View on GitHub (pinned to 9690622007)
Solutions
- Include a non-empty string 'delivery_id' in the JSON body: {"delivery_id": "<id>"}
- Alternatively include a well-formed issue reference: {"issue": "owner/repo#123"}
- Ensure the request has Content-Type: application/json and the body is actually sent
- Convert numeric/UUID delivery values to strings before sending
Example fix
// before
await fetch('/retry', { method: 'POST', body: JSON.stringify({}) });
// after
await fetch('/retry', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ delivery_id: String(deliveryId) }) }); Defensive patterns
Strategy: validation
Validate before calling
// Ensure exactly one valid target field before calling retry
const body = deliveryId
? { delivery_id: String(deliveryId) }
: { issue: `${owner}/${repo}#${number}` };
if (!body.delivery_id && !body.issue) throw new Error('retry needs delivery_id or issue'); Type guard
function hasRetryTarget(b: unknown): b is { delivery_id?: string; issue?: string } {
const o = b as Record<string, unknown>;
return (typeof o?.delivery_id === 'string' && o.delivery_id.length > 0) ||
(typeof o?.issue === 'string' && o.issue.length > 0);
} Try / catch
try {
await api.retry(body);
} catch (err) {
if (err.status === 400 && /retry requires/.test(err.message)) {
logger.error('retry call missing target', { body });
} else throw err;
} Prevention
- Always send the body with Content-Type: application/json
- Stringify delivery ids — the server only accepts string values
- Keep one shared client function for retry so the target field is never forgotten
- Validate the body in CI tests against the endpoint contract
When it happens
Trigger: POSTing to the retry endpoint with a body missing both 'delivery_id' and 'issue' — e.g. `{}`, `{'delivery_id': ''}` (empty string), `{'delivery_id': 123}` (not a string), or `{'issue': None}`. The guard is `isinstance(delivery_id, str) and delivery_id` / `isinstance(issue_ref, str) and issue_ref`.
Common situations: Forgetting the JSON body entirely or sending it with the wrong Content-Type so the body parses to empty; a client serializing an undefined/null variable; integer delivery IDs being sent where a string is required; renaming the parameter in a client without updating it server-side.
Understand the failure class
Background: Missing required parameter errors: what 'X is required' and 'the required X param is missing' mean, and how to fix them — this error's family across 27 libraries.
Related errors
- cancel requires 'delivery_id'
- {str(exc)} (ManualTriageError)
- Invalid GitHub release metadata
- Provider ${providerName}: "api" is required when registering
- Provider ${providerName}, model ${modelDef.id}: no "api" spe
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/be391a14a7aafa30.
Report an issue: GitHub.