medusajs/medusa · error · CloudServiceError
CloudServiceError propagated from non-ok response (body.mess
Error message
CloudServiceError propagated from non-ok response (body.message, status ${response.status}) What it means
The Medusa search HTTP client wraps any non-2xx response from the cloud search service in a CloudServiceError, propagating the remote body's type/originalType/data/message plus the HTTP status. This is the transport-level surfacing of upstream API failures (auth, not-found, bad request, service errors).
Source
Thrown at packages/modules/search/src/providers/search-medusa/utils/client.ts:114
const headers: Record<string, string> = {
"Content-Type": "application/json",
Authorization: `Basic ${this.options_.api_key}`,
"x-medusa-environment-handle": this.options_.environment_handle,
}
const response = await fetch(`${this.options_.endpoint}${path}`, {
method,
headers: {
...options.headers,
...headers,
},
body: options.body ? JSON.stringify(options.body) : undefined,
})
const body = await response.json().catch(() => ({}))
if (!response.ok) {
throw new CloudServiceError(
body.type,
body.originalType,
body.data,
body.message,
response.status
)
}
return body as T
}
}
export class MedusaSearchIndex {
constructor(
protected readonly client_: MedusaSearchClient,
protected readonly name_: string
) {}
View on GitHub (pinned to 5e06e544a2)
Solutions
- Inspect the CloudServiceError status and message to identify the cause (401/403 -> credentials, 404 -> index/handle, 400 -> payload)
- Verify api_key, endpoint, and environment_handle provider options against the cloud dashboard
- If the index is missing, create it (createIndex / loadIndex) before writing
- Retry with backoff for transient 5xx statuses
Defensive patterns
Strategy: retry
Type guard
const isCloudServiceError = (e) => e instanceof Error && "status" in e && typeof e.status === "number"
Try / catch
for (let attempt = 0; attempt < 3; attempt++) {
try { return await client.write(...) } catch (e) {
if (isCloudServiceError(e) && e.status >= 500 && attempt < 2) {
await new Promise((r) => setTimeout(r, 2 ** attempt * 500)); continue
}
throw e
}
} Prevention
- Treat 401/403 as credential rotation: monitor key expiry and alert before it lapses
- Create indexes before first write in provisioning scripts
- Wrap batch jobs with retry-on-5xx and dead-letter the failing batch with its status code
When it happens
Trigger: Any client operation — createIndex, page, schema, metadata, updateSchema, or write — where the remote endpoint returns a non-ok status: expired/invalid api_key (401/403), unknown index/environment handle (404), malformed query payload (400), or upstream outage (5xx).
Common situations: Expired or rotated API keys, wrong endpoint or environment_handle in provider options, an index not yet created when writing documents, or transient 5xx outages of the Medusa cloud search service during reindex jobs.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- invalid_data
- invalid_data
- Deleting Medusa search documents requires filters
- Medusa search accepts at most ${MAX_MULTI_QUERIES} queries p
- A Medusa search document exceeds the ${MAX_WRITE_BYTES}-byte
AI-assisted analysis of medusajs/medusa@5e06e544a2 (2026-08-27).
Data as JSON: /api/errors/4d3431f04b2a6081.
Report an issue: GitHub.