Errors
The typed MedblocksError hierarchy with instanceof discrimination.
Every non-2xx response from the Medblocks API is parsed into a typed subclass of MedblocksError. Discriminate at the catch site with instanceof and log error.requestId in every branch.
Hierarchy
MedblocksError base - every API error extends this
├── MedblocksAuthenticationError 401 - missing / invalid / expired key
├── MedblocksPermissionError 403 - authenticated but not allowed
├── MedblocksInvalidRequestError 400 - validation failure (see error.param)
├── MedblocksNotFoundError 404 - resource not in your org
├── MedblocksConflictError 409 - duplicate id, state-machine violation
├── MedblocksRateLimitError 429 - quota exceeded (see error.retryAfter)
├── MedblocksEhrError 502 - upstream EHR failed
└── MedblocksApiError 500 - unexpected Medblocks-side errorMedblocksSignatureError is a separate class for webhook signature verification. It never carries an HTTP status.
Fields On Every Error
| Field | Type | Source |
|---|---|---|
type | string | error.type from the envelope |
code | string | error.code. Stable, machine-readable |
message | string | error.message. Human readable |
param | string | null | error.param. The offending field, when known |
docUrl | string | error.doc_url. Link to the relevant docs page |
requestId | string | error.request_id or the X-Request-Id response header |
statusCode | number | HTTP status |
MedblocksRateLimitError additionally carries retryAfter: number | null parsed from the Retry-After header (seconds, or null if unparseable).
Discriminating With instanceof
import {
MedblocksAuthenticationError,
MedblocksConflictError,
MedblocksInvalidRequestError,
MedblocksNotFoundError,
MedblocksRateLimitError,
MedblocksError,
} from "@medblocks/connect";
try {
await mb.patientFlow.init(input);
} catch (err) {
if (err instanceof MedblocksAuthenticationError) {
// 401 - surface a "check your API key" message in your alerting
} else if (err instanceof MedblocksInvalidRequestError) {
// 400 - err.param tells you which field
console.error("invalid", { param: err.param, code: err.code, requestId: err.requestId });
} else if (err instanceof MedblocksConflictError) {
// 409 - e.g. external_id_already_exists
} else if (err instanceof MedblocksNotFoundError) {
// 404
} else if (err instanceof MedblocksRateLimitError) {
// 429 - wait err.retryAfter seconds
} else if (err instanceof MedblocksError) {
// anything else - log it
} else {
throw err;
}
}The base MedblocksError is also a catch-all for any future error type the API adds. New types are returned as base MedblocksError instances rather than as a TypeScript miss.
Common Codes By Subclass
| Subclass | Codes you’ll see |
|---|---|
MedblocksAuthenticationError | missing_api_key, invalid_api_key, expired_api_key, not_authenticated |
MedblocksPermissionError | forbidden, insufficient_scope, org_access_denied, role_insufficient |
MedblocksInvalidRequestError | bad_request, invalid_data, unsupported_api_version, payload_too_large |
MedblocksNotFoundError | resource_not_found |
MedblocksConflictError | external_id_already_exists, resource_conflict, webhook_endpoint_limit_reached |
MedblocksRateLimitError | throttled, quota_exceeded |
MedblocksEhrError | oauth_error, token_exchange_failed, token_unavailable, fhir_error, storage_error, email_error |
MedblocksApiError | internal_error, db_error, config_missing, unexpected_response, invalid_response |
The full list is on API Errors.
Webhook Signature Errors
MedblocksSignatureError is thrown by Medblocks.webhooks.constructEvent when an incoming delivery fails verification. It carries reason, not a status code:
reason | Cause |
|---|---|
missing_header | No Medblocks-Signature header on the request. |
malformed_header | Header did not match t=<sec>,v1=<hex>. |
timestamp_expired | t outside the tolerance window (default 5 min). |
signature_mismatch | HMAC mismatch. Wrong secret or tampered body. |
malformed_body | Body was not valid JSON in the event envelope shape. |
import { MedblocksSignatureError } from "@medblocks/connect";
try {
const event = await Medblocks.webhooks.constructEvent(rawBody, sigHeader, secret);
// ...
} catch (err) {
if (err instanceof MedblocksSignatureError) {
console.warn("signature failed", err.reason);
return new Response("bad signature", { status: 400 });
}
throw err;
}Logging
requestId is the single most useful field in a support ticket. Always log it on the error path:
catch (err) {
if (err instanceof MedblocksError) {
logger.error("medblocks api error", {
type: err.type,
code: err.code,
requestId: err.requestId,
statusCode: err.statusCode,
param: err.param,
});
}
throw err;
}Retries
The SDK retries transient network errors and 429 / 502 / 503 / 504 responses automatically. See Advanced · Retries. Errors that surface to your code have already been retried up to maxNetworkRetries times (default 3).
429 honors the server’s Retry-After header during the SDK’s internal retries. If retries are exhausted, the final MedblocksRateLimitError carries retryAfter for your own backoff logic.
Related
- API Errors. Wire envelope and full code list.
- SDK · Advanced. Retry behavior.
- Webhooks · Signatures. Verification flow and the
MedblocksSignatureErrorreasons.
