sone centraldocs
Try the interactive chat

Sample store

Sone assistant

Hello! Ask me about linen shirts, shipping or our size guide.

Uses sample data; does not start a real conversation.

Errors

Error response formats, every error code, retry rules and recovery steps.

Errors use OpenAI's error format. OpenAI SDKs convert them into their own error classes.

This format applies to the documented JSON endpoints. Unknown paths or incorrect HTTP methods return PocketBase's 404 format with status, message and data, without an error field.

{
  "error": {
    "message": "Bu tarayıcı anahtarı bu sitede kullanılamaz. Siteyi anahtarın izinli siteleri arasına ekleyin.",
    "type": "permission_error",
    "param": null,
    "code": "origin_not_allowed"
  }
}
  • message is a simple, visitor-facing Turkish explanation. The example above preserves the actual server language.
  • code is stable and English. Always branch on code, not message.
  • param identifies the invalid field, such as model, messages, input or after, or is null when no field applies.

POST /chat is the exception: its body is plain Turkish text containing the message. Vercel AI SDK exposes it as useChat's error.message. The code appears in X-Sone-Error-Code; this header is available to server requests, but is not exposed to browser code.

Codes

Do not repeat the same request when x-should-retry is false. Retry-After is the wait specified by that header.

Statuscodex-should-retryRetry-AfterMeaning and recovery
400invalid_bodynonenoneBody is empty or unreadable. Send a JSON body.
400invalid_jsonnonenoneInvalid JSON or an incorrect field type. See message for details.
400missing_user_messagenonenoneThe final message must be a user message containing text.
400invalid_rolenonenoneUnknown message role, or a Responses message item without a role.
400invalid_contentnonenoneMessage content is not a string or an array of parts.
400unsupported_contentnonenoneA new message contains an image, audio or file. Send text only.
400message_too_longnonenoneA new message exceeds 4,000 characters. Shorten it.
400too_many_new_messagesnonenoneMore than 12 new visitor messages in one request. Include the assistant reply in history before continuing, or start a new conversation.
400tools_not_supportednonenoneRemove tools, functions or function-call items. The assistant uses the business tools configured in Sonecentral.
400unsupported_parameternonenonen is not 1, response_format or text.format is not text, or background is true. param identifies the field.
400missing_inputnonenoneResponses request has no input.
400invalid_inputnonenoneResponses input is not text or an array of items.
400unsupported_itemnonenoneUnknown Responses input item type.
400conflicting_parametersnonenoneprevious_response_id and conversation were supplied together. Use one.
400instructions_too_longnonenoneResponses instructions exceeds 2,000 characters or 4 KB JSON.
400invalid_metadatanonenoneResponses metadata exceeds 16 keys, 64 characters per key, 512 characters per string value, or 4 KB JSON. Values must be strings.
400safety_identifier_too_longnonenoneResponses safety_identifier exceeds 64 characters.
400user_too_longnonenoneResponses user exceeds 64 characters.
400previous_response_id_too_longnonenoneTrimmed previous_response_id is longer than a response ID. Send the original response id.
400item_id_too_longnonenoneAn item_reference ID exceeds 64 characters.
400conversation_model_mismatchfalsenoneThe conversation belongs to another assistant. Use the same model or start a new conversation.
400conversation_fullfalsenoneThe conversation has reached 200 visitor messages. Start a new one.
400invalid_cursornonenoneafter is not a message ID in this conversation. Clear the cursor and read from the start.
400not_cancellablenonenoneResponses complete within the request; there is no background task to cancel.
401missing_api_keynonenoneNo key supplied.
401invalid_api_keynonenoneUnknown or malformed key, or prefix does not match its type.
401revoked_api_keynonenoneThe key was revoked. Create a new one.
402plan_requiredfalsenoneThe workspace plan does not permit assistant replies. The assistant did not reply.
403origin_not_allowednonenonePublishable key used without Origin or outside its allowed origins. Add the site to the key.
403secret_key_in_browsernonenoneA server key was used from a browser. Use a publishable key.
404model_not_foundnonenoneNo published assistant with this ID is available to the key. GET /models lists available assistants.
404conversation_not_foundnonenoneNot an API conversation in this workspace, or its assistant is unavailable to the key. Clear the saved ID and start a new conversation.
404previous_response_not_foundnonenoneThe referenced response is missing, deleted, was created with store: false, or belongs to an assistant unavailable to the key.
404response_not_foundnonenoneStored response is missing, deleted, older than 30 days or unavailable to the key. On DELETE, also returned when another key stored it.
404file_not_foundnonenoneInvalid or expired signed URL. Read conversation messages again to obtain a fresh URL.
409conversation_busynone2The previous turn is still running. This message was not stored. Wait and retry with the same Idempotency-Key.
413request_too_largenonenoneBody exceeds 1 MB. Send the conversation ID instead of the full history.
422idempotency_key_reusedfalsenoneThe same Idempotency-Key was used with different text. Use a new key for each new message.
429rate_limit_exceedednoneWindow-dependentRequest or read limit exceeded. Wait for Retry-After.
429ai_turn_ceilingfalse300The workspace hourly/daily API reply limit, or its publishable-key share, was reached. The assistant did not reply.
429assistant_quota_exhaustedfalsenoneSonecentral AI capacity is temporarily unavailable. Your workspace has not exhausted a plan allowance; API replies do not consume it. The assistant did not reply.
429file_download_limitnoneWindow-dependentThis file ID was downloaded 10 times in the last hour. Wait for Retry-After.
429file_egress_limitnoneUntil midnight UTCWorkspace daily file download limit reached.
503assistant_pausedIf delivered to team false60Automatic replies are disabled. The assistant did not reply.
503assistant_unavailablenone30The assistant is temporarily unavailable. Wait and retry with the same Idempotency-Key.
503conversation_not_creatednonenoneThe conversation could not be created. Retry later.
503message_not_storednonenoneThe message could not be stored. Retry with the same Idempotency-Key.
503messages_unavailablenonenoneConversation messages could not be read. Retry on the next poll.
503file_unavailablenonenoneThe file is temporarily unavailable. Retry later.
503response_not_deletednonenoneThe stored response could not be deleted. Retry later.

Retry-After is measured in seconds and rounded up.

Two other cases may use a different body: more than 120 file-download requests per minute from one address returns a non-OpenAI 429; unexpected server errors may also have another format. Retry unexpected 5xx responses with the same Idempotency-Key.

Where messages go when the assistant cannot reply

plan_required, assistant_quota_exhausted, ai_turn_ceiling and assistant_paused mean the assistant could not reply:

  • Existing conversation: the visitor message is stored and delivered to the team. The Turkish message says it was forwarded, and for assistant_quota_exhausted also says a team member will reply. Read replies from conversation messages.
  • First message: nothing is stored and no conversation is created. The Turkish message asks the visitor to try later.

assistant_unavailable also has two cases. If the turn never started, nothing happened and the message asks the visitor to retry later. If the turn started and then failed, the visitor message was stored and the explanation says it was forwarded to the team. Retrying with the same key does not store it twice and lets the assistant answer it.

type values

typeErrors
invalid_request_error400, 404, 409, 413, 422
authentication_error401
permission_error403
insufficient_quota402 plan_required, 429 assistant_quota_exhausted
rate_limit_error429 rate_limit_exceeded, ai_turn_ceiling, file_download_limit, file_egress_limit
server_error503

Response headers

HeaderPurpose
x-request-idRequest ID, present on every response. Include it when contacting support.
retry-afterSeconds to wait before retrying.
x-should-retryfalse means do not repeat the same request. OpenAI SDKs respect it automatically.
x-sone-conversation-idConversation ID, included in turn responses and at the start of streams.
x-sone-error-codeError code for POST /chat only. Not exposed to browser code.

Browser code can read x-request-id, retry-after, x-should-retry and x-sone-conversation-id.

Retrying

  • Do not retry when x-should-retry: false. This applies to plan_required, assistant_quota_exhausted, ai_turn_ceiling, idempotency_key_reused, conversation_model_mismatch, conversation_full, and assistant_paused when the message reached the team.
  • If Retry-After is present without x-should-retry: false, wait that long. It is provided for rate_limit_exceeded, conversation_busy, assistant_paused, assistant_unavailable, file_download_limit and file_egress_limit. ai_turn_ceiling also includes it, but must not be retried automatically.
  • For 503 without Retry-After, or a network failure, resend the same request with the same Idempotency-Key. Back off for 1, 2, 4 and 8 seconds. The message is not stored twice. See Retries, including the publishable-key network-address exception.
  • conversation_busy is a race: two turns were sent concurrently. Disable sending until the current turn finishes.
  • Other 4xx errors require correcting the request.

OpenAI SDKs retry 408, 409, 429 and 5xx twice by default. They respect x-should-retry and wait for retry-after values up to 60 seconds. They do not add Idempotency-Key; pass it in request options: Chat Completions.

Errors during streaming

Key, limit, assistant, conversation and plan checks run before streaming begins, even with "stream": true. Rejections return normal HTTP errors. Once streaming starts, the HTTP status cannot change, so the server writes an error and closes the stream:

  • Chat Completions: data: {"error": {…}}, using the error object above, followed by data: [DONE]. OpenAI SDKs throw this as an error.
  • Responses: an error event with type, code, message, param and sequence_number, then response.failed. The failed response has status: "failed" and the same code and message in error. No [DONE] follows. OpenAI's Node SDK throws APIError on error, with the code at error.code; Python delivers an event with type: "error".
  • Vercel AI SDK: {"type":"error","errorText":"…"}, followed by data: [DONE]. useChat changes status to error and exposes the text through error.message.

Possible post-start errors are ai_turn_ceiling if the limit is reached mid-turn, and assistant_unavailable if the turn fails. Messages sent before the error were stored; recover them through GET /conversations/{id}/messages.

What to show visitors

You can display message, but a clear next step is often better. For 429 and 503, say you cannot reply now and ask the visitor to try later. In an existing conversation, ai_turn_ceiling, assistant_quota_exhausted, plan_required or assistant_paused means the message reached your team; explain that the team will reply in this chat. Do not display raw error codes to visitors.