Skip to main content

Errors

Errors use conventional HTTP status codes and a single JSON body shape.

{
"code": "insufficient_scope",
"message": "This API key does not hold the required scope: operations.write",
"statusCode": 403
}

Every response carries x-request-id. Log it — it identifies your exact request in MineTech's logs and is the first thing support will ask for.

Status codes

StatusMeaningRetry?
400Malformed requestNo — fix the request
401Authentication failedNo — see Authentication
403Authenticated but not permittedNo — grant the scope
404No such resource, or it belongs to another tenantNo
409Conflicting stateDepends — read the message
422Validation failedNo — see fieldErrors
429Rate limit exceededYes — honour Retry-After
5xxServer-side failureYes — with backoff

A 404 on a resource you believe exists usually means it belongs to a different tenant. Tenant scoping is applied before existence checks, deliberately: a 403 would confirm the record exists to someone not entitled to know that.

Validation errors

{
"code": "validation_failed",
"statusCode": 422,
"message": "title should not be empty; severity must be a valid enum value",
"fieldErrors": {
"title": ["should not be empty"],
"severity": ["must be a valid enum value"]
}
}

Handling errors with the SDK

Every failure is a typed subclass:

import {
ApiError, ValidationError, RateLimitError,
PermissionError, TimeoutError, ConnectionError,
} from '@minetech/node/errors';

try {
await client.safety.incidents.create(payload);
} catch (error) {
if (error instanceof ValidationError) {
return showFieldErrors(error.fieldErrors);
}
if (error instanceof PermissionError) {
return alertOperator(`Key is missing a scope: ${error.message}`);
}
if (error instanceof RateLimitError) {
return scheduleRetry(error.retryAfterSeconds);
}
if (error instanceof TimeoutError || error instanceof ConnectionError) {
// Already retried internally; the network is genuinely unavailable.
return markDegraded();
}
if (error instanceof ApiError) {
log.error({ status: error.status, code: error.code, requestId: error.requestId });
}
throw error;
}

The SDK retries 408, 429 and 5xx automatically with exponential backoff and jitter, honouring Retry-After. By the time an error reaches you, retrying has already been attempted and failed.

4xx responses are never retried — they would fail identically, and retrying only delays the error you need to see.