Skip to content

Response Codes

All endpoints return {"code": "xxxx", "msg": "...", "data": ...} with HTTP status fixed at 200; the business outcome is carried by code.

Source: app/core/code.py. The frontend .env maps select codes to behaviors (logout / modal logout / auto-refresh / silent fail).

Code segments

RangeMeaning
0000Success
1000–1999System internal error (caught exceptions, validation failure)
2000–2999Framework-builtin business errors (auth, permission, conflict, Schema required, etc.)
3000–3999Framework-reserved (currently unused)
4000–9999Project / business-module codes (module codes must start at 4000; never reuse 2xxx)

0000 — Success

CodeConstantMeaning
0000Code.SUCCESSRequest succeeded

1xxx — System internal

10xx — Server errors

CodeConstantMeaning
1000INTERNAL_ERRORGeneric / unhandled exception

11xx — Database errors

CodeConstantMeaning
1100INTEGRITY_ERRORUnique / FK constraint violation
1101NOT_FOUNDRecord does not exist (DoesNotExist)

12xx — Validation

CodeConstantMeaning
1200REQUEST_VALIDATIONRequest param / body validation failed (FastAPI layer)
1201RESPONSE_VALIDATIONResponse serialization failed

1200's data.errors is [{field, message, type}], translated by _format_validation_error in exceptions.py.

2xxx — Business logic

21xx — Authentication (frontend has special handling)

CodeConstantMeaningFrontend behavior
2100INVALID_TOKENToken missing / decode failed / format invalidRedirect to login
2101INVALID_SESSIONWrong token type / user not foundRedirect to login
2102ACCOUNT_DISABLEDAccount disabledModal then logout
2103TOKEN_EXPIREDAccess token expiredAuto-refresh
2104REFRESH_TOKEN_MISSINGRefresh token missing
2105NOT_REFRESH_TOKENProvided token is not a refresh token
2106SESSION_INVALIDATEDtoken_version was incremented; old token invalidRedirect to login

Frontend .env: VITE_SERVICE_LOGOUT_CODES=2100,2101,2104,2105, VITE_SERVICE_MODAL_LOGOUT_CODES=2102,2106, VITE_SERVICE_EXPIRED_TOKEN_CODES=2103.

22xx — Authorization

CodeConstantMeaning
2200API_DISABLEDEndpoint disabled by admin
2201PERMISSION_DENIEDRBAC API permission denied
2202MISSING_BUTTON_PERMISSIONrequire_buttons(..., require_all=True) missing some
2203NEED_ANY_BUTTON_PERMISSIONrequire_buttons(...) missing all
2204MISSING_ROLErequire_roles(..., require_all=True) missing some
2205NEED_ANY_ROLErequire_roles(...) missing all
2206SUPER_ADMIN_ONLYSuper-admin only
2207USER_NO_ROLEUser has no role assigned

23xx — Resource conflicts

CodeConstantMeaning
2300DUPLICATE_RESOURCEGeneric duplicate (catch-all)
2301DUPLICATE_ROLE_CODERole code exists
2302DUPLICATE_USER_EMAILEmail registered
2303DUPLICATE_USER_PHONEPhone registered
2304DUPLICATE_USER_NAMEUsername exists
2305DUPLICATE_MENU_ROUTEMenu route path exists

24xx — Generic business failure

CodeConstantMeaning
2400FAILUncategorized failure (avoid; add a specific code)
2401WRONG_CREDENTIALSWrong username / password
2402CAPTCHA_INVALIDCaptcha invalid or expired
2403CAPTCHA_SEND_FAILEDCaptcha send failed
2404PHONE_NOT_REGISTEREDPhone not registered
2405OLD_PASSWORD_WRONGOld password wrong on change-password
2406TARGET_USER_NOT_FOUNDTarget user not found (e.g. impersonate)

25xx — Rate limit / security

CodeConstantMeaning
2500RATE_LIMITEDToo many requests
2501IP_BANNEDIP temporarily banned
2502ACCESS_DENIEDBlocked by security policy

26xx — Required field (raised in business schemas)

CodeConstantMeaning
2600PARAM_REQUIREDGeneric required (catch-all)
2601USERNAME_REQUIREDUsername required
2602PASSWORD_REQUIREDPassword required
2603USER_ROLE_REQUIREDUser must have at least one role
2604USER_EMAIL_REQUIREDUser email required
2605ROLE_NAME_REQUIREDRole name required
2606ROLE_CODE_REQUIREDRole code required
2607ROUTE_NAME_REQUIREDRoute name required
2608ROUTE_PATH_REQUIREDRoute path required

4000–9999 — Project-defined

Project-specific codes. The framework doesn't touch them; the frontend doesn't auto-pop errors — handle as you wish.

Module convention: business module codes must start at 4000 (do not occupy the 2xxx system range). Append your module's range at the end of app/core/code.py (e.g. 41xx, 42xx). One unique code per failure scenario — never re-use 2400.

40xx — HR business (sample of module-specific codes)

CodeConstantMeaning
4000HR_DEPARTMENT_REQUIREDSuper-admin must specify department on employee create
4001HR_MANAGER_REQUIREDOnly department managers may create employees
4002HR_CREATE_FORBIDDENNo permission to create employee
4003HR_TAGS_EXCEED_LIMITEmployee tag count over limit
4004HR_EMPLOYEE_NOT_IN_DEPTEmployee not in current manager's department
4005HR_USER_NOT_EMPLOYEECurrent user is not bound to an employee
4006HR_MANAGER_ONLYOnly department managers may perform this
4007HR_INVALID_TRANSITIONDisallowed state transition

Raising

python
from app.utils import BizError, Code, Fail

# A: raise (recommended; transparent across layers)
raise BizError(code=Code.HR_INVALID_TRANSITION, msg="invalid transition")

# B: return Fail (api layer only; more direct)
return Fail(code=Code.OLD_PASSWORD_WRONG, msg="old password wrong")

SchemaValidationError (extends BizError) is for Pydantic validators: it does not extend ValueError, so Pydantic won't catch it — it reaches the global handler with the original code.

Frontend mapping

Frontend .envDefaultBehavior
VITE_SERVICE_SUCCESS_CODE0000Treat as success, extract data
VITE_SERVICE_LOGOUT_CODES2100,2101,2104,2105Force logout
VITE_SERVICE_MODAL_LOGOUT_CODES2102,2106Modal then logout
VITE_SERVICE_EXPIRED_TOKEN_CODES2103Auto-refresh + retry
OthersShow msg as error

基于 MIT 协议发布