hcengineering/platform · error · ApiError
err.code
err.code
Error message
err.message
What it means
The global Express error middleware maps ApiError instances to HTTP 400 with the error's code and message. Any handler that throws/rejects with an ApiError (validation failures, bad requests) lands here.
Source
Thrown at services/gmail/pod-gmail/src/server.ts:53
app.use(cors())
app.use(express.json())
endpoints.forEach((endpoint) => {
if (endpoint.type === 'get') {
app.get(endpoint.endpoint, catchError(endpoint.handler))
} else if (endpoint.type === 'post') {
app.post(endpoint.endpoint, catchError(endpoint.handler))
}
})
app.use((_req, res, _next) => {
res.status(404).send({ message: 'Not found' })
})
app.use((err: any, _req: any, res: any, _next: any) => {
if (err instanceof ApiError) {
res.status(400).send({ code: err.code, message: err.message })
return
}
res.status(500).send({ message: err.message })
})
return app
}
export function listen (e: Express, port: number, host?: string): Server {
const cb = (): void => {
console.log(`Gmail service has been started at ${host ?? '*'}:${port}`)
}
return host !== undefined ? e.listen(port, host, cb) : e.listen(port, cb)
}
View on GitHub (pinned to 63e28dc964)
Solutions
- Read the returned code field to identify which ApiError subclass fired
- Correct the request payload/token that failed validation
- Inspect the failing endpoint's controller to see which inputs throw ApiError
- Wrap client calls to parse the { code, message } shape for actionable feedback
Example fix
// before
const data = await res.json()
console.log(data)
// after
const data = await res.json()
if (!res.ok && data.code) {
throw new Error(`Request rejected (${data.code}): ${data.message}`)
} Defensive patterns
Strategy: type-guard
Validate before calling
// validate inputs that controllers typically reject with ApiError
if (!token || !socialId) throw new Error('token and socialId are required') Type guard
function isApiErrorResponse(body: unknown): body is { code: string; message: string } {
return typeof body === 'object' && body !== null && 'code' in body && 'message' in body
} Try / catch
try {
const res = await fetch(url, opts)
const body = await res.json()
if (res.status === 400 && isApiErrorResponse(body)) {
throw new ApiClientError(body.code, body.message)
}
return body
} catch (e) {
if (e instanceof ApiClientError) { /* branch on e.code */ }
throw e
} Prevention
- Read the `code` field — it identifies the exact validation that failed
- Branch on known ApiError codes to give users actionable feedback
- Fix the offending payload/token rather than retrying; 400s are deterministic
When it happens
Trigger: Any endpoint handler (e.g. via catchError wrapper) throws an ApiError — invalid input decoded by controllers, malformed tokens, or business-rule rejections.
Common situations: Clients sending payloads that fail controller validation; decodeToken throwing a token-related ApiError; upstream services returning ApiError subclasses that propagate uncaught to the router.
Related errors
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/8a37ee64eba25968.
Report an issue: GitHub.