Heads-up: AdCP 3.0.5 details.status placeholder is being consolidated in 3.1
AdCP 3.0.5 shipped error-details/agent-permission-denied.json carrying a placeholder shape for per-agent commercial-status rejections:
{
"code": "PERMISSION_DENIED",
"details": {
"scope": "agent",
"status": "suspended" // or "blocked"
}
}
That shape was a placeholder while the dedicated codes were being designed. AdCP 3.1 (PR adcontextprotocol/adcp#3906, in flight) consolidates the placeholder into two dedicated error codes:
| Before (3.0.5) |
After (3.1) |
code: PERMISSION_DENIED, details: { scope: "agent", status: "suspended" } |
code: AGENT_SUSPENDED (no details payload) |
code: PERMISSION_DENIED, details: { scope: "agent", status: "blocked" } |
code: AGENT_BLOCKED (no details payload) |
code: PERMISSION_DENIED, details: { scope: "agent", reason: "sandbox_only" } |
unchanged |
The dedicated codes carry recovery: "terminal" directly at the wire level (the placeholder shape inherited PERMISSION_DENIED's correctable, which contradicted the no-retry MUST). The status field is removed from agent-permission-denied.json in 3.1 — this is not a deprecation window; envelopes carrying details.status will fail schema validation against 3.1.
Action
If this SDK has integrated against the 3.0.5 placeholder shape:
- Switch any code that emits
PERMISSION_DENIED + scope:"agent" + status:"suspended"|"blocked" to emit AGENT_SUSPENDED / AGENT_BLOCKED directly.
- Switch any code that consumes
details.status to branch on error.code === 'AGENT_SUSPENDED' | 'AGENT_BLOCKED' instead.
- The
PERMISSION_DENIED + scope:"agent" + reason:"sandbox_only" path is unchanged and stays.
If this SDK has not integrated against the placeholder yet, no action — just integrate against the 3.1 shape directly when the dedicated codes land.
References
Heads-up: AdCP 3.0.5
details.statusplaceholder is being consolidated in 3.1AdCP 3.0.5 shipped
error-details/agent-permission-denied.jsoncarrying a placeholder shape for per-agent commercial-status rejections:{ "code": "PERMISSION_DENIED", "details": { "scope": "agent", "status": "suspended" // or "blocked" } }That shape was a placeholder while the dedicated codes were being designed. AdCP 3.1 (PR adcontextprotocol/adcp#3906, in flight) consolidates the placeholder into two dedicated error codes:
code: PERMISSION_DENIED, details: { scope: "agent", status: "suspended" }code: AGENT_SUSPENDED(nodetailspayload)code: PERMISSION_DENIED, details: { scope: "agent", status: "blocked" }code: AGENT_BLOCKED(nodetailspayload)code: PERMISSION_DENIED, details: { scope: "agent", reason: "sandbox_only" }The dedicated codes carry
recovery: "terminal"directly at the wire level (the placeholder shape inheritedPERMISSION_DENIED'scorrectable, which contradicted the no-retry MUST). Thestatusfield is removed fromagent-permission-denied.jsonin 3.1 — this is not a deprecation window; envelopes carryingdetails.statuswill fail schema validation against 3.1.Action
If this SDK has integrated against the 3.0.5 placeholder shape:
PERMISSION_DENIED + scope:"agent" + status:"suspended"|"blocked"to emitAGENT_SUSPENDED/AGENT_BLOCKEDdirectly.details.statusto branch onerror.code === 'AGENT_SUSPENDED' | 'AGENT_BLOCKED'instead.PERMISSION_DENIED + scope:"agent" + reason:"sandbox_only"path is unchanged and stays.If this SDK has not integrated against the placeholder yet, no action — just integrate against the 3.1 shape directly when the dedicated codes land.
References