Files

13 KiB

HTTP Error Contract (RFC7807 + Stable Codes)

This document is the single source of truth for backend HTTP error transport format and frontend parsing strategy.

Response Format

All API errors must use application/problem+json and include RFC7807 fields.

{
  "type": "about:blank",
  "title": "Unprocessable Entity",
  "status": 422,
  "detail": "Validation failed",
  "code": "TODO_TITLE_REQUIRED",
  "params": {
    "field": "title"
  },
  "instance": "/api/v1/todo"
}

Field Rules

  • code (required for business errors): stable machine-readable code (UPPER_SNAKE_CASE)
  • params (optional): key-value values for localized message placeholders
  • detail (required by RFC7807): human-readable fallback/debug text

Backend Rules

  • Do not rely on free-text detail as the only contract.
  • New endpoints and new error branches must return stable code.
  • Existing branches can migrate incrementally but must prefer code-first.
  • Keep status semantics unchanged (400/401/403/404/409/422/429/5xx).

Frontend Parsing Rules

  • Parse in this order: code -> params -> status -> fallback detail.
  • User-facing text should come from local l10n mapping by code.
  • Unknown code fallback:
    1. status-based generic localized message
    2. safe fallback localized message (do not expose raw internals)

Error Code Registry (Single Source of Truth)

This section is the canonical registry shared by backend and frontend.

When creating/modifying/deprecating any code, this table must be updated in the same change.

Code Domain HTTP Meaning
AGENT_RUN_INPUT_INVALID agent 422 Run input payload invalid
AGENT_RUN_MESSAGES_INVALID agent 422 Run messages contract invalid
AGENT_INVALID_RUN_ID agent 422 SSE runId query invalid
AGENT_INVALID_LAST_EVENT_ID agent 422 SSE Last-Event-ID invalid
AGENT_SSE_CONNECTION_LIMIT agent 429 SSE connections exceed per-user limit
AGENT_ATTACHMENT_EMPTY agent 422 Attachment payload empty
AGENT_ATTACHMENT_TOO_LARGE agent 413 Attachment exceeds allowed size
AGENT_AUDIO_UNSUPPORTED_FORMAT agent 400 Audio content type/header unsupported
AGENT_AUDIO_TOO_LARGE agent 400 Audio exceeds allowed size
AGENT_AUDIO_EMPTY agent 400 Audio payload empty
AGENT_ASR_UNAVAILABLE agent 502 ASR dependency unavailable
AGENT_FORBIDDEN agent 403 Current user does not own target thread/session
AGENT_PAYLOAD_INVALID agent 422 Run payload or forwarded runtime mode is invalid
AGENT_ATTACHMENTS_TOO_MANY agent 422 Attachments exceed per-message limit
AGENT_SIGNED_IMAGE_URL_INVALID agent 422 Signed image URL is malformed or unverifiable
AGENT_ATTACHMENT_STORAGE_UNAVAILABLE agent 503 Attachment storage backend unavailable
AGENT_ATTACHMENT_UNSUPPORTED_TYPE agent 422 Attachment MIME type is unsupported
AGENT_ATTACHMENT_UPLOAD_FAILED agent 502 Upload to attachment storage failed
AGENT_ATTACHMENT_BUCKET_INVALID agent 422 Attachment bucket does not match allowed bucket
AGENT_ATTACHMENT_PATH_SCOPE_INVALID agent 422 Attachment path is outside allowed user scope
AGENT_SIGNED_URL_GENERATION_FAILED agent 502 Failed to generate signed URL from storage backend
AGENT_SESSION_ID_INVALID agent 422 Session ID is not a valid UUID
AGENT_SESSION_NOT_FOUND agent 404 Agent chat session does not exist
AGENT_USER_ID_INVALID agent 422 User ID is not a valid UUID
AGENT_UPSTREAM_CONNECTION_ERROR agent 503 Upstream AI service connection failed (network/proxy issue)
INVALID_BINARY_URL_HOST agent 422 Signed URL host is invalid
INVALID_BINARY_URL_BUCKET agent 422 Signed URL bucket is invalid
INVALID_BINARY_URL_PATH_SCOPE agent 422 Signed URL path scope is invalid
AUTH_SERVICE_UNAVAILABLE auth 503 Upstream auth service is temporarily unavailable
AUTH_TOO_MANY_REQUESTS auth 429 Auth operation exceeds request rate limit
AUTH_VERIFICATION_CODE_INVALID auth 401 OTP verification code is invalid
AUTH_REFRESH_TOKEN_INVALID auth 401 Refresh token is invalid or expired
AUTH_REFRESH_TOKEN_MISSING auth 401 Refresh token is missing for logout/refresh
AUTH_USER_NOT_FOUND auth 404 User lookup by phone returns no match
AUTH_UNAUTHORIZED auth 401 Authorization header or token is invalid
ANALYTICS_LOGIN_PASSWORD_INVALID analytics 401 Analytics dashboard password is invalid
ANALYTICS_AUTH_HEADER_MISSING analytics 401 Authorization header is missing when reading analytics data
ANALYTICS_AUTH_SCHEME_INVALID analytics 401 Authorization scheme is invalid; Bearer token required
ANALYTICS_AUTH_TOKEN_MISSING analytics 401 Bearer token is missing
ANALYTICS_TOKEN_MALFORMED analytics 401 Analytics token format is malformed
ANALYTICS_TOKEN_SIGNATURE_INVALID analytics 401 Analytics token signature verification failed
ANALYTICS_TOKEN_PAYLOAD_INVALID analytics 401 Analytics token payload cannot be parsed
ANALYTICS_TOKEN_EXPIRED analytics 401 Analytics token is expired
ANALYTICS_DATE_FORMAT_INVALID analytics 400 Analytics date must use YYYY-MM-DD format
ANALYTICS_FILE_NOT_FOUND analytics 404 Analytics day file does not exist
JWT_VERIFIER_NOT_CONFIGURED auth 503 JWT verifier configuration is missing
AUTOMATION_JOB_LIMIT_EXCEEDED automation_jobs 400 User-created automation jobs exceed allowed limit
AUTOMATION_SYSTEM_JOB_MODIFICATION_FORBIDDEN automation_jobs 403 System bootstrap job cannot be modified
AUTOMATION_JOB_NOT_FOUND automation_jobs 404 Target automation job does not exist or is not owned by user
AUTOMATION_JOB_STORE_UNAVAILABLE automation_jobs 503 Automation job persistence unavailable
NOT_FOUND runtime/tooling 404 Resource/tool target not found
LOOKUP_FAILED runtime/tooling 500 Lookup or resolution failed
INTERNAL_ERROR runtime/tooling 500 Internal execution error
MISSING_RUNTIME_ARGS runtime/tooling 400 Required runtime arguments missing
TOOL_PENDING_APPROVAL runtime/tooling 409 Tool call awaiting approval
TOOL_REJECTED runtime/tooling 403 Tool call rejected by policy/user
USER_STORE_UNAVAILABLE users 503 User storage or database access unavailable
USER_NOT_FOUND users 404 Requested user profile not found
USER_UPDATE_FIELDS_EMPTY users 400 Update request contains no writable fields
USER_AVATAR_UNSUPPORTED_TYPE users 422 Avatar MIME type is unsupported
USER_AVATAR_TOO_LARGE users 413 Avatar file size exceeds configured limit
USER_AVATAR_EMPTY users 422 Avatar upload payload is empty
USER_AVATAR_UPLOAD_FAILED users 502 Upstream storage upload failed
USER_AUTH_LOOKUP_UNAVAILABLE users 503 Auth/identity phone lookup backend unavailable
TODO_SERVICE_UNAVAILABLE todo 503 Todo persistence unavailable
TODO_NOT_FOUND todo 404 Todo item does not exist
TODO_ACCESS_FORBIDDEN todo 403 Current user cannot operate on target todo
TODO_REORDER_DUPLICATE_ID todo 400 Reorder payload contains duplicate todo IDs
TODO_STATUS_INVALID todo 400 Todo status filter value invalid
TODO_PRIORITY_INVALID todo 400 Todo priority filter value out of range
SCHEDULE_ITEM_INVALID_TIME_RANGE schedule_items 400 end_at must be after start_at
SCHEDULE_ITEM_STORE_UNAVAILABLE schedule_items 503 Schedule item persistence unavailable
SCHEDULE_ITEM_NOT_FOUND schedule_items 404 Schedule item does not exist
SCHEDULE_ITEM_START_AT_TIMEZONE_REQUIRED schedule_items 400 start_at must include timezone when end_at is set
SCHEDULE_ITEM_PAGE_INVALID schedule_items 400 Pagination page must be greater than or equal to 1
SCHEDULE_ITEM_PAGE_SIZE_INVALID schedule_items 400 Pagination page_size out of allowed range
SCHEDULE_ITEM_SHARE_FORBIDDEN schedule_items 403 Current user cannot share this schedule item
SCHEDULE_ITEM_SHARE_TARGET_NOT_FRIEND schedule_items 403 Recipient must be an accepted friend of current user
SCHEDULE_ITEM_FORBIDDEN schedule_items 403 Current user does not have permission to edit this schedule item
SCHEDULE_ITEM_SHARE_PERMISSION_EXCEEDED schedule_items 403 Requested share permission exceeds inviter permission
SCHEDULE_ITEM_SUBSCRIPTION_ALREADY_ACTIVE schedule_items 400 Recipient already has active subscription
SCHEDULE_ITEM_INVITE_ALREADY_SUBSCRIBED schedule_items 400 Recipient already accepted calendar invite
SCHEDULE_ITEM_INVITE_ALREADY_PENDING schedule_items 400 Recipient already has pending calendar invite
SCHEDULE_ITEM_AUTH_LOOKUP_UNAVAILABLE schedule_items 503 Auth/identity lookup unavailable when sharing
SCHEDULE_ITEM_ACTOR_LOOKUP_UNAVAILABLE schedule_items 503 Actor profile lookup unavailable when constructing inbox change payload
SCHEDULE_ITEM_PENDING_INVITE_NOT_FOUND schedule_items 404 No pending invitation exists for target item/user
SCHEDULE_ITEM_ACCEPT_SUBSCRIPTION_FAILED schedule_items 503 Subscription accept flow failed unexpectedly
SCHEDULE_ITEM_REJECT_SUBSCRIPTION_FAILED schedule_items 503 Subscription reject flow failed unexpectedly
SCHEDULE_ITEM_DATETIME_TIMEZONE_REQUIRED schedule_items 400 Datetime input must include timezone
SCHEDULE_ITEM_DATETIME_REQUIRED schedule_items 400 Required datetime input missing
INBOX_MESSAGE_NOT_FOUND inbox_messages 404 Inbox message does not exist for current user
INBOX_MESSAGE_STORE_UNAVAILABLE inbox_messages 503 Inbox message persistence unavailable
INBOX_SSE_CONNECTION_LIMIT inbox_messages 429 SSE connections exceed per-user limit
INBOX_INVALID_LAST_EVENT_ID inbox_messages 422 SSE Last-Event-ID format invalid
INBOX_EVENT_STREAM_UNAVAILABLE inbox_messages 503 Inbox SSE stream read unavailable
MEMORIES_USER_NOT_FOUND memories 404 User memory record does not exist
MEMORIES_WORK_NOT_FOUND memories 404 Work memory record does not exist
MEMORIES_SERVICE_UNAVAILABLE memories 503 Memories persistence unavailable
FRIEND_REQUEST_SELF_NOT_ALLOWED friendships 400 User cannot send friend request to self
FRIEND_ALREADY_ACCEPTED friendships 400 Users are already friends
FRIEND_REQUEST_BLOCKED friendships 400 Friend request blocked by relationship status
FRIEND_REQUEST_ALREADY_SENT friendships 400 Pending friend request already exists
FRIENDSHIP_SERVICE_UNAVAILABLE friendships 503 Friendship persistence unavailable
FRIEND_REQUEST_NOT_FOUND friendships 404 Friend request record not found
FRIEND_REQUEST_FORBIDDEN friendships 403 Current user is not allowed for this friend request action
FRIEND_REQUEST_NOT_PENDING friendships 400 Friend request is not in pending state
FRIEND_INBOX_MESSAGE_NOT_FOUND friendships 404 Friend request inbox message not found
FRIENDSHIP_DATA_INVALID friendships 400 Friendship record is missing required linkage fields
FRIENDSHIP_NOT_FOUND friendships 404 Friendship record not found
FRIENDSHIP_REMOVE_REQUIRES_ACCEPTED friendships 400 Only accepted friendships can be removed

Registry Coverage Check

当前仓库未内置自动校验脚本,维护流程按以下约束执行:

  • 更新本文件错误码时,同步检查前端映射文件:apps/lib/data/network/error_code_mapper.dart
  • 任何新增/变更/废弃错误码必须在同一 PR 中完成「协议文档 + 前端映射 + 后端返回码」三方对齐
  • 若后续补充自动校验脚本,需在本节追加命令与输出约定

Agent Error Code Set

Agent

  • AGENT_RUN_INPUT_INVALID
  • AGENT_RUN_MESSAGES_INVALID
  • AGENT_INVALID_RUN_ID
  • AGENT_INVALID_LAST_EVENT_ID
  • AGENT_SSE_CONNECTION_LIMIT
  • AGENT_ATTACHMENT_EMPTY
  • AGENT_ATTACHMENT_TOO_LARGE
  • AGENT_AUDIO_UNSUPPORTED_FORMAT
  • AGENT_AUDIO_TOO_LARGE
  • AGENT_AUDIO_EMPTY
  • AGENT_ASR_UNAVAILABLE
  • AGENT_FORBIDDEN
  • AGENT_PAYLOAD_INVALID
  • AGENT_ATTACHMENTS_TOO_MANY
  • AGENT_SIGNED_IMAGE_URL_INVALID
  • AGENT_ATTACHMENT_STORAGE_UNAVAILABLE
  • AGENT_ATTACHMENT_UNSUPPORTED_TYPE
  • AGENT_ATTACHMENT_UPLOAD_FAILED
  • AGENT_ATTACHMENT_BUCKET_INVALID
  • AGENT_ATTACHMENT_PATH_SCOPE_INVALID
  • AGENT_SIGNED_URL_GENERATION_FAILED
  • AGENT_SESSION_ID_INVALID
  • AGENT_SESSION_NOT_FOUND
  • AGENT_USER_ID_INVALID
  • AGENT_UPSTREAM_CONNECTION_ERROR

Compatibility Strategy

  • Transition phase keeps detail and adds code/params.
  • Frontend moves to code-first mapping first; backend can then continue migrating remaining endpoints.