Error Shape Taxonomy
Overview
มาตรฐาน error response format ที่ใช้ทั้งองค์กร ครอบคลุม error codes, categories, และ structure ที่ทำให้ client และ monitoring tools เข้าใจ error ได้ทันที
Why This Matters
- Debuggability: รู้ทันทีว่า error มาจากไหน ทำไม
- Client handling: Frontend/mobile handle errors ได้ถูกต้อง
- Monitoring: Alert และ dashboard แยก error types ได้
- Documentation: Error catalog ที่ reference ได้
Core Concepts
1. Error Envelope Structure
- แนะนำให้ยึดแนวคิด RFC 7807 (problem details) แต่ให้คงโครงเดียวกันทั้งองค์กร
- ต้องมี:
code, message, requestId, timestamp, status
- ถ้าเป็น retryable ให้มี
retryable และ retryAfterSeconds (ถ้ามี)
2. Error Code System
PREFIX_### หรือ PREFIX_SUB_### (อ่านง่าย, stable)
- code ต้อง คงที่ (ห้ามเปลี่ยนความหมาย) และต้อง document ใน catalog
- หลีกเลี่ยงใช้ HTTP status เป็น code (เช่น
ERR_500) เพราะไม่สื่อสาเหตุ
3. Error Categories
กำหนดหมวดให้ชัดเพื่อ routing/alert:
AUTH_ / AUTHZ_: authn/authz
VAL_: validation / malformed requests
BIZ_: business/domain rules
RATE_: rate limiting / quotas
SYS_: infra/system dependencies (DB, queue, upstream)
4. Error Messages
message ต้องเป็น user-safe (ไม่เปิดเผย stacktrace/SQL/secret)
- รายละเอียดเชิงเทคนิคให้ใส่ใน
details (และต้อง scrub PII/secret)
- ถ้าต้องการข้อความที่ UI แสดง ให้มี
userMessage แยก (optional) และรองรับ i18n
5. Error Context
- ทุก error ต้องมี
requestId (correlation) และควรมี traceId ถ้ามี tracing
path และ method ช่วย debug ได้เร็ว (optional)
- stacktrace ห้ามส่งกลับ client; ให้เก็บใน logs เท่านั้น
6. Localization
- ถ้ารองรับหลายภาษา: client ใช้
Accept-Language และ server map เป็น userMessage
- ไม่ควร encode ภาษาไว้ใน
code (code ควรเป็นภาษากลาง)
7. Error Mapping
- map internal errors → external errors แบบ deterministic และทดสอบได้
- errors จาก upstream ต้อง normalize เข้าสู่ shape มาตรฐานของเรา
status ต้องสะท้อน semantics (เช่น VAL_ ส่วนใหญ่เป็น 400/422)
8. Error Documentation
- มี “error catalog” ต่อ service หรือองค์กร:
code, status, meaning, client action, retryable
- ใช้เป็นแหล่งข้อมูลสำหรับ client SDK, docs, และ alert routing
Quick Start
export type ErrorCategory = "AUTH" | "AUTHZ" | "VAL" | "BIZ" | "RATE" | "SYS";
export interface ErrorResponse {
error: {
code: string;
category: ErrorCategory;
message: string;
status: number;
requestId: string;
timestamp: string;
path?: string;
method?: string;
retryable?: boolean;
retryAfterSeconds?: number;
details?: Record<string, unknown>;
validationErrors?: Array<{ field: string; reason: string }>;
};
}
Production Checklist
Standard Error Shape
// Example payload (VAL_)
// {
// "error": {
// "code": "VAL_001",
// "category": "VAL",
// "message": "Invalid request",
// "status": 422,
// "requestId": "req-789",
// "timestamp": "2024-01-15T10:00:00Z",
// "validationErrors": [
// { "field": "email", "reason": "Invalid email format" }
// ]
// }
// }
Error Code Taxonomy
| Prefix |
Category |
Example |
| AUTH_ |
Authentication |
AUTH_001 Token expired |
| AUTHZ_ |
Authorization |
AUTHZ_001 Permission denied |
| VAL_ |
Validation |
VAL_001 Invalid email format |
| BIZ_ |
Business logic |
BIZ_001 Insufficient balance |
| SYS_ |
System |
SYS_001 Database unavailable |
| RATE_ |
Rate limiting |
RATE_001 Too many requests |
Status + Retryability Guidelines
401/403: ไม่ควร retry แบบอัตโนมัติ (ต้องแก้ credential/permission)
400/422: ไม่ควร retry (ต้องแก้ request)
409: retry ได้ในบางกรณี (ใช้ backoff) ถ้าเป็น conflict ชั่วคราว
429: retry ได้ โดยใช้ Retry-After
503/504: retry ได้ (bounded retries + jitter)
Anti-patterns
- Generic errors: "Something went wrong"
- Leaking internals: Stack traces to client
- Inconsistent shape: Different format per service
- Missing correlation: No request ID
- Changing meaning: เปลี่ยน semantics ของ code เดิม ทำให้ client/alert พัง
Integration Points
- API gateways (error transformation)
- Frontend error boundaries
- Monitoring/alerting
- Documentation generators
Further Reading
1---2name: error-shape-taxonomy3description: Standard error response taxonomy and envelope for services, including error codes, categories, retryability, correlation IDs, safe messaging, and validation error details4---5
6# Error Shape Taxonomy
7
8## Overview
9
10มาตรฐาน error response format ที่ใช้ทั้งองค์กร ครอบคลุม error codes, categories, และ structure ที่ทำให้ client และ monitoring tools เข้าใจ error ได้ทันที
11
12## Why This Matters
13
14- **Debuggability**: รู้ทันทีว่า error มาจากไหน ทำไม
15- **Client handling**: Frontend/mobile handle errors ได้ถูกต้อง
16- **Monitoring**: Alert และ dashboard แยก error types ได้
17- **Documentation**: Error catalog ที่ reference ได้
18
19---
20
21## Core Concepts
22
23### 1. Error Envelope Structure
24
25- แนะนำให้ยึดแนวคิด RFC 7807 (problem details) แต่ให้คงโครงเดียวกันทั้งองค์กร
26- ต้องมี: `code`, `message`, `requestId`, `timestamp`, `status`
27- ถ้าเป็น retryable ให้มี `retryable` และ `retryAfterSeconds` (ถ้ามี)
28
29### 2. Error Code System
30
31- `PREFIX_###` หรือ `PREFIX_SUB_###` (อ่านง่าย, stable)
32- code ต้อง **คงที่** (ห้ามเปลี่ยนความหมาย) และต้อง document ใน catalog
33- หลีกเลี่ยงใช้ HTTP status เป็น code (เช่น `ERR_500`) เพราะไม่สื่อสาเหตุ
34
35### 3. Error Categories
36
37กำหนดหมวดให้ชัดเพื่อ routing/alert:
38
39- `AUTH_` / `AUTHZ_`: authn/authz
40- `VAL_`: validation / malformed requests
41- `BIZ_`: business/domain rules
42- `RATE_`: rate limiting / quotas
43- `SYS_`: infra/system dependencies (DB, queue, upstream)
44
45### 4. Error Messages
46
47- `message` ต้องเป็น **user-safe** (ไม่เปิดเผย stacktrace/SQL/secret)
48- รายละเอียดเชิงเทคนิคให้ใส่ใน `details` (และต้อง scrub PII/secret)
49- ถ้าต้องการข้อความที่ UI แสดง ให้มี `userMessage` แยก (optional) และรองรับ i18n
50
51### 5. Error Context
52
53- ทุก error ต้องมี `requestId` (correlation) และควรมี `traceId` ถ้ามี tracing
54- `path` และ `method` ช่วย debug ได้เร็ว (optional)
55- stacktrace ห้ามส่งกลับ client; ให้เก็บใน logs เท่านั้น
56
57### 6. Localization
58
59- ถ้ารองรับหลายภาษา: client ใช้ `Accept-Language` และ server map เป็น `userMessage`
60- ไม่ควร encode ภาษาไว้ใน `code` (code ควรเป็นภาษากลาง)
61
62### 7. Error Mapping
63
64- map internal errors → external errors แบบ deterministic และทดสอบได้
65- errors จาก upstream ต้อง normalize เข้าสู่ shape มาตรฐานของเรา
66- `status` ต้องสะท้อน semantics (เช่น `VAL_` ส่วนใหญ่เป็น `400/422`)
67
68### 8. Error Documentation
69
70- มี “error catalog” ต่อ service หรือองค์กร: `code`, `status`, `meaning`, `client action`, `retryable`
71- ใช้เป็นแหล่งข้อมูลสำหรับ client SDK, docs, และ alert routing
72
73## Quick Start
74
75```typescript
76export type ErrorCategory = "AUTH" | "AUTHZ" | "VAL" | "BIZ" | "RATE" | "SYS";
77
78export interface ErrorResponse {
79 error: {
80 code: string;
81 category: ErrorCategory;
82 message: string;
83 status: number;
84 requestId: string;
85 timestamp: string;
86 path?: string;
87 method?: string;
88 retryable?: boolean;
89 retryAfterSeconds?: number;
90 details?: Record<string, unknown>;
91 validationErrors?: Array<{ field: string; reason: string }>;
92 };
93}
94```
95
96## Production Checklist
97
98- [ ] All errors follow standard shape
99- [ ] Error codes documented in catalog
100- [ ] User-safe messages (no sensitive data)
101- [ ] Request ID included in all errors
102- [ ] Error logging consistent
103
104## Standard Error Shape
105
106```typescript
107// Example payload (VAL_)
108// {
109// "error": {
110// "code": "VAL_001",
111// "category": "VAL",
112// "message": "Invalid request",
113// "status": 422,
114// "requestId": "req-789",
115// "timestamp": "2024-01-15T10:00:00Z",
116// "validationErrors": [
117// { "field": "email", "reason": "Invalid email format" }
118// ]
119// }
120// }
121```
122
123## Error Code Taxonomy
124
125| Prefix | Category | Example |
126|--------|----------|---------|
127| AUTH_ | Authentication | AUTH_001 Token expired |
128| AUTHZ_ | Authorization | AUTHZ_001 Permission denied |
129| VAL_ | Validation | VAL_001 Invalid email format |
130| BIZ_ | Business logic | BIZ_001 Insufficient balance |
131| SYS_ | System | SYS_001 Database unavailable |
132| RATE_ | Rate limiting | RATE_001 Too many requests |
133
134## Status + Retryability Guidelines
135
136- `401/403`: ไม่ควร retry แบบอัตโนมัติ (ต้องแก้ credential/permission)
137- `400/422`: ไม่ควร retry (ต้องแก้ request)
138- `409`: retry ได้ในบางกรณี (ใช้ backoff) ถ้าเป็น conflict ชั่วคราว
139- `429`: retry ได้ โดยใช้ `Retry-After`
140- `503/504`: retry ได้ (bounded retries + jitter)
141
142## Anti-patterns
143
1441. **Generic errors**: "Something went wrong"
1452. **Leaking internals**: Stack traces to client
1463. **Inconsistent shape**: Different format per service
1474. **Missing correlation**: No request ID
1485. **Changing meaning**: เปลี่ยน semantics ของ code เดิม ทำให้ client/alert พัง
149
150## Integration Points
151
152- API gateways (error transformation)
153- Frontend error boundaries
154- Monitoring/alerting
155- Documentation generators
156
157## Further Reading
158
159- [RFC 7807 Problem Details](https://datatracker.ietf.org/doc/html/rfc7807)
160- [API Error Handling Best Practices](https://apisyouwonthate.com/blog/creating-good-api-errors-in-rest-graphql-and-grpc)