Chapter 6

Errors and limits

How to read the errors that come back, and the limits you are most likely to meet.

The shape of an error

Errors come back in the Connect RPC format. The HTTP status matches the code, and message carries an explanation that can be shown to the person in front of you.

HTTP/1.1 403 Forbidden
{
  "code": "permission_denied",
  "message": "権限がありません。自分と同等以上の権限を持つユーザーは操作できません。"
}
message comes back in Japanese today, as the samples on this page show. If your service serves another language, key your own wording off code and reason rather than off the text.

The codes

codeHTTPMeaningWhat to do
invalid_argument400The input is not validShow the message and let them correct it
unauthenticated401Not signed in, or the credential is no longer goodRefresh the token; sign them in again if that fails
permission_denied403Not allowedRetrying will not help. Hide the action instead
not_found404No such thing, or the token is not validFetch the list again
already_exists409Already registeredA duplicate email address, for instance
failed_precondition412Something has to happen firstSee the section below — the reason header says which
resource_exhausted429A rate limit was reachedWait before retrying. Retrying at once achieves nothing
internal500A fault on our sideSend us the requestId
A 500 response carries a requestId. Investigating a fault needs that value, so keep it in your own logs as well.

412: when a code is needed first

Calls that reach personal data, and calls that cannot be undone, need the account to have proved itself again. When it has not, the call is refused with 412 and an X-Step-Up-Reason header saying which of three situations it is. The three need different things from the person, so branch on the header rather than on the message text.

X-Step-Up-ReasonSituationWhat the person has to do
step_up_enroll_requiredThe account has no second factor at allRegister an authenticator app first
step_up_requiredRegistered, but this session has not been asked yetEnter a code once; it lasts the session
step_up_staleThe short window for a heavy operation has lapsedEnter a code again, immediately before the operation
HTTP/1.1 412 Precondition Failed
X-Step-Up-Reason: step_up_required
{
  "code": "failed_precondition",
  "message": "この機能を利用するには、認証コードの入力が必要です。",
  "reason": "step_up_required"
}
An API key can never satisfy this, because there is nobody to ask for a code. A key that calls one of these endpoints gets 403 rather than 412, so that a client does not retry for ever.
The header is exposed through CORS, so a browser can read it. The same value is also in the body as reason.

412: other preconditions

SituationWhat it means
The tenant has been stoppedThe tenant has no owner who can act. Reading it and leaving it still work; nothing can be changed until somebody takes it over.
No tenant is selectedTenant-scoped calls act on the selected tenant. Call TenantService/SelectTenant first.
The account signs in with Google or AppleIt has no password, and one cannot be set. Password change and password reset are refused.

403: what an API key may not do

SituationWhat it means
A read-only key attempted a changeNew keys are READ_ONLY unless READ_WRITE was chosen when issuing. Issue a new key with the scope you need.
The call needs a code firstA key has nobody to ask for one, so it is refused outright rather than with a 412 that would invite retrying for ever. This covers far more than changes — see below.
In practice a key can call only VerifyToken, GetCurrentUser and ListMyTenants. Everything else — including listing members and listing keys — is behind the code requirement and therefore closed to keys. Design your integration around the token verification flow rather than around reading data.

Rate limits

WhatLimitCounted per
Sign-in5 / 15 minaccount
Sign-in30 / 15 minsource address
Registration3 / hoursource address
Password reset request3 / houraccount
Password reset request10 / hoursource address
Token refresh20 / 15 minsession
Authenticator code attempts5 / 15 minaccount
Email change request5 / houraccount
Avatar upload20 / houraccount
Request to join a tenant10 / houraccount
API key requests600 / minkey
Everything, as a ceiling300 / minsource address
Sign-in attempts are limited per account as well. Failing repeatedly locks the rightful user out for a while, so do not retry automatically.
API keys get their own allowance so that a busy integration calling from one server is not held to the same ceiling as an attacker on one machine. Exceeding the address-level ceiling turns that address away for ten minutes.

Other limits

ItemLimit
Access token lifetime15 minutes
Refresh token lifetime14 days
Session lifetime14 days, and it does not extend
Password length8–128 characters
Avatar image2MB, JPEG / PNG / WebP / GIF
API key lifetime30 days by default, 90 at most
Live API keysPer tenant: 2 on Free, 3 on Light, 20 on Pro
Tenants one account may create3 by default, raisable per account
Members in one tenant10 on Free, 50 on Light, 500 on Pro. Outstanding invitations count toward it.
Outstanding invitations50 per account
Invitation link lifetime7 days
Tenant nameUnique among tenants that still exist
Email confirmation link24 hours
Password reset link1 hour
Authenticator challenge at sign-in5 minutes
Step-up window for heavy operations15 minutes
Objection period for taking over a tenant14 days