REQ-C-028: ALREADY_EXISTS Response Pattern
Tier: Command Contract | Priority: P1
Source: Silent assumption — agents retry failed creates; if create fails because the resource already exists, the agent needs the existing resource returned so it can proceed without a separate get call
Addresses: Severity: High / Token Spend: Medium / Time: Medium / Context: Low
Description
Commands that create resources MUST handle the "resource already exists" case by returning a structured ALREADY_EXISTS response — not a generic error. The response MUST include the existing resource in the data field (identical to what a get command would return), set "ok": false, use exit code from the command's declared exit code table (a dedicated code, not 1), and set "retryable": false.
This pattern allows agents that retry failed creates to recover gracefully: they receive the existing resource and can proceed as if the create succeeded. Without this pattern, agents must make a separate get call after every create failure to determine whether the failure was a conflict or a genuine error.
The inverse — delete on a non-existent resource — MUST exit 0 with {"ok": true, "data": {"status": "not_found"}}.
Acceptance Criteria
tool resource create --name foocalled twice returns the resource on both calls- Second call:
"ok": false, exit codeALREADY_EXISTS(declared in exit code table),datacontains the existing resource - Agent can use
datafrom the second call directly without a follow-upget - Delete of non-existent resource exits
0with structurednot_foundconfirmation - Both
ALREADY_EXISTSandNOT_FOUND(on delete) are declared in the command's exit code table
Schema
exit-code-entry — commands must declare an ALREADY_EXISTS exit code entry; response-envelope carries the existing resource in data
Wire Format
Create called on existing resource:
{
"ok": false,
"data": {
"id": "res_123",
"name": "foo",
"created_at": "2026-01-01T00:00:00Z",
"status": "active"
},
"error": {
"code": "ALREADY_EXISTS",
"message": "Resource 'foo' already exists",
"retryable": false,
"conflict_id": "res_123"
}
}
Delete called on non-existent resource:
{
"ok": true,
"data": {"status": "not_found", "id": "res_999"},
"error": null
}
Example
Agent create-or-get pattern:
result = run("tool resource create --name foo")
if result.exit_code == 0:
resource = result.data # newly created
elif result.error.code == "ALREADY_EXISTS":
resource = result.data # existing — no extra get call needed
else:
raise result.error # genuine failure
Related
| Requirement | Tier | Relationship |
|---|---|---|
| REQ-C-007 | C | Composes: idempotency key prevents ALREADY_EXISTS on intentional retries |
| REQ-C-003 | C | Provides: effect field distinguishes create (non-idempotent) from apply (idempotent) |
| REQ-C-001 | C | Provides: ALREADY_EXISTS exit code must be declared in the command's exit code table |
| REQ-F-004 | F | Provides: response envelope that carries the existing resource in data on conflict |