Error Catalog — GIW POC Identity Platform
Status: POC · Date: 2026-09-21
1. Standard error model
Every custom API returns the same shape on failure:
{
"code": "EMPLOYEE_VERIFICATION_FAILED",
"message": "Unable to verify employee information",
"correlationId": "corr-9b1f2c7e-1a2b-4c3d-8e9f-0a1b2c3d4e5f",
"timestamp": "2026-09-21T04:30:00.000Z"
}
Rules:
codeis stable and machine-readable. Clients branch on it, never onmessage.messageis for a human reading a log. It is deliberately vague about why an identity check failed.correlationIdis always present and always matches theX-Correlation-IDresponse header.- No error body ever contains a CCCD, a token, a password, or a stack trace.
2. Catalog
| Code | HTTP | Raised by | Meaning | Client should |
|---|---|---|---|---|
INVALID_REQUEST |
400 | all | Malformed JSON, missing field, or a field failing its pattern | Fix the request; do not retry unchanged |
UNAUTHORIZED |
401 | all | Missing, malformed, expired or untrusted credential | Re-authenticate |
FORBIDDEN |
403 | Entitlement | Credential valid but the request is not permitted — e.g. a body subjectId contradicting the token |
Do not retry; this is a bug or an attack |
NOT_FOUND |
404 | all | No such endpoint or resource | — |
EMPLOYEE_VERIFICATION_FAILED |
401 (form re-render) | Authenticator | Employee ID and CCCD did not match a record. Identical for "unknown id" and "wrong CCCD". | Let the user retry, up to the attempt cap |
EMPLOYEE_INACTIVE |
401 (form re-render) | Authenticator / HR | Record matched but the employee is not ACTIVE | Direct the user to HR, not to retry |
HR_SERVICE_TIMEOUT |
504 → 503 page | HR / Authenticator | HR did not answer within the timeout, after retries | Back off and retry later. Never fall back to granting access. |
HR_SERVICE_UNAVAILABLE |
503 | HR / Authenticator | HR returned 5xx, was unreachable, or rejected the service credential | Back off; alert operations |
IDENTITY_LINK_CONFLICT |
409 | Authenticator | More than one Keycloak user carries this employee_ref |
Stop. Manual data fix required. |
ENTITLEMENT_DENIED |
403 · 422 | Entitlement · Session | 403: the subject is not entitled. 422: a grant was attempted with no entitlementId. |
Show the reason; do not retry the same request |
SESSION_NOT_FOUND |
404 | Session | No session with that id | Create a new session |
SESSION_EXPIRED |
409 | Session | Session is REVOKED or EXPIRED and cannot be granted | Create a new session |
RATE_LIMITED |
429 | HR | Too many failed verification attempts against one employee record, or the global ceiling was hit. Successful verifications are never counted | Back off ~60 s. Do not retry immediately — a retry makes the queue worse |
DMN_UNAVAILABLE |
503 | Entitlement | The decision engine did not answer. Fails closed: an engine that cannot answer is not an answer of "no" | Back off; alert operations |
DMN_EVALUATION_ERROR |
422 | DMN | The model loaded but could not evaluate — a modelling bug, not a denial | Fix the .dmn; do not treat as refused |
MODEL_NOT_FOUND |
404 | DMN | No decision model by that name | Check GET /api/v1/decisions |
INTERNAL_ERROR |
500 | all | Unhandled server error | Retry once, then alert |
3. Denial reasons on ENTITLEMENT_DENIED
The 403 body carries an extra reason:
reason |
Meaning |
|---|---|
EMPLOYEE_NOT_VERIFIED |
Token claims user_type=EMPLOYEE but carries no employee_verified=true. Should be unreachable; if it fires, the claim mapping is broken. |
COMPANY_NOT_ELIGIBLE |
Company is not in EMPLOYEE_COMPANIES. Demonstrated by test employee PTX10001 (PARTNER-X). |
UNKNOWN_USER_TYPE |
user_type present but unrecognised. A missing user_type is not an error — it is treated as CUSTOMER. |
4. User-facing messages
The authenticator returns message keys, resolved by the theme bundle in Vietnamese and English.
| Key | Vietnamese | English |
|---|---|---|
employeeVerifyFailed |
Không xác minh được thông tin. Vui lòng kiểm tra lại mã nhân viên và số CCCD. | We could not verify those details. |
employeeVerifyMissingFields |
Vui lòng nhập đủ hai ô. | Please fill in both fields. |
employeeVerifyInvalidFormat |
Vui lòng kiểm tra định dạng thông tin đã nhập. | Please check the format of the details you entered. |
employeeVerifyInactive |
Hồ sơ nhân viên không ở trạng thái hoạt động. Vui lòng liên hệ nhân sự. | This employee record is not active. |
employeeVerifyNotEligible |
Hồ sơ này không thuộc diện dùng Wi-Fi trên tàu bay. | This employee record is not eligible for onboard Wi-Fi. |
employeeVerifyHrTimeout |
Hệ thống nhân sự phản hồi chậm. Vui lòng thử lại. | The HR system did not respond in time. |
employeeVerifyHrUnavailable |
Hệ thống nhân sự tạm thời không truy cập được. | The HR system is unavailable. |
employeeVerifyRateLimited |
Thử quá nhiều lần. Vui lòng bắt đầu lại. | Too many attempts. Please start again. |
employeeLinkConflict |
Tìm thấy nhiều hồ sơ trùng cho nhân viên này. Vui lòng liên hệ hỗ trợ. | We found more than one record for this employee. |
Note that employeeVerifyFailed deliberately does not say which field was wrong.
5. What must never appear in an error
| Forbidden | Why |
|---|---|
| The CCCD, whole or partial | Sensitive personal data |
| Any distinction between "no such employee" and "wrong CCCD" | Enumeration |
| A token, key or password | Credential disclosure |
| A stack trace or internal hostname | Reconnaissance |
| The raw HR response | Minimal disclosure |
| Whether the HR service credential was rejected | A 401 from HR surfaces to the user as "unavailable" |