REQ-F-063: Credential Expiry Structured Error
Tier: Framework-Automatic | Priority: P1
Source: §53 Credential Expiry Mid-Session
Addresses: Severity: Critical / Token Spend: High / Time: High / Context: Low
Description
The framework MUST distinguish between three credential failure modes and emit structured errors with distinct exit codes and machine-readable fields for each: (1) Never authenticated — exit 8, error.code: UNAUTHENTICATED, with hint pointing to the login command; (2) Credentials expired — exit 10, error.code: CREDENTIALS_EXPIRED, with error.expires_at (ISO-8601), error.refresh_command (exact CLI invocation to renew); (3) Insufficient permissions — exit 8, error.code: PERMISSION_DENIED, with error.required_permission. The framework intercepts HTTP 401/403 responses from its HTTP client and maps them to these structured errors automatically. Commands declare their required credential scopes via required_scopes: [].
Acceptance Criteria
- An expired token produces exit 10 with
error.code: "CREDENTIALS_EXPIRED"anderror.refresh_command - A missing token produces exit 8 with
error.code: "UNAUTHENTICATED"andhintpointing to the auth command - A valid token with insufficient scope produces exit 8 with
error.code: "PERMISSION_DENIED"anderror.required_permission - An agent can distinguish expiry from denial by exit code alone (10 vs 8) without parsing error text
Schema
Types: response-envelope.md · exit-code.md
The framework maps HTTP 401/403 responses to structured ErrorDetail objects. Credential expiry uses TIMEOUT (10); missing or invalid credentials use AUTH_REQUIRED (8).
Wire Format
{
"ok": false,
"data": null,
"error": {
"code": "CREDENTIALS_EXPIRED",
"message": "Access token expired at 2025-03-01T00:00:00Z",
"retryable": true,
"expires_at": "2025-03-01T00:00:00Z",
"refresh_command": "mytool auth refresh"
},
"warnings": [],
"meta": { "duration_ms": 120 }
}
Example
Framework-Automatic: no command author action needed. The framework intercepts HTTP 401/403 from its HTTP client and maps them to the appropriate structured error.
# Expired token → exit 10, CREDENTIALS_EXPIRED
$ mytool deploy --json
{
"ok": false,
"data": null,
"error": {
"code": "CREDENTIALS_EXPIRED",
"message": "Token expired at 2025-03-01T00:00:00Z",
"retryable": true,
"expires_at": "2025-03-01T00:00:00Z",
"refresh_command": "mytool auth refresh"
},
...
}
→ exit 10; agent runs refresh_command then retries
# Missing token → exit 8, UNAUTHENTICATED
$ mytool deploy --json
{
"ok": false, "data": null,
"error": { "code": "UNAUTHENTICATED", "hint": "Run: mytool auth login", "retryable": false },
...
}
→ exit 8; agent runs auth login flow
Related
| Requirement | Tier | Relationship |
|---|---|---|
| REQ-F-001 | F | Provides: AUTH_REQUIRED (8) and TIMEOUT (10) exit codes used for credential failures |
| REQ-F-004 | F | Provides: ResponseEnvelope shape for the credential error responses |
| REQ-F-037 | F | Composes: network-level HTTP error context is merged into the credential error detail |
| REQ-F-034 | F | Composes: credential values in error details are redacted from logs |