{"record":{"id":"4d3431f04b2a6081","repo":"medusajs/medusa","slug":"cloudserviceerror-propagated-from-non-ok-response","errorCode":null,"errorMessage":"CloudServiceError propagated from non-ok response (body.message, status ${response.status})","messagePattern":"CloudServiceError propagated from non-ok response \\(body\\.message, status (.+?)\\)","errorType":"http","errorClass":"CloudServiceError","httpStatus":null,"severity":"error","filePath":"packages/modules/search/src/providers/search-medusa/utils/client.ts","lineNumber":114,"sourceCode":"    const headers: Record<string, string> = {\n      \"Content-Type\": \"application/json\",\n      Authorization: `Basic ${this.options_.api_key}`,\n      \"x-medusa-environment-handle\": this.options_.environment_handle,\n    }\n\n    const response = await fetch(`${this.options_.endpoint}${path}`, {\n      method,\n      headers: {\n        ...options.headers,\n        ...headers,\n      },\n      body: options.body ? JSON.stringify(options.body) : undefined,\n    })\n\n    const body = await response.json().catch(() => ({}))\n\n    if (!response.ok) {\n      throw new CloudServiceError(\n        body.type,\n        body.originalType,\n        body.data,\n        body.message,\n        response.status\n      )\n    }\n\n    return body as T\n  }\n}\n\nexport class MedusaSearchIndex {\n  constructor(\n    protected readonly client_: MedusaSearchClient,\n    protected readonly name_: string\n  ) {}\n","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/medusajs/medusa/blob/5e06e544a296b9033f20f71f11c559f81a0e5739/packages/modules/search/src/providers/search-medusa/utils/client.ts#L96-L132","documentation":"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).","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":"const isCloudServiceError = (e) =>\n  e instanceof Error && \"status\" in e && typeof e.status === \"number\"","tryCatchPattern":"for (let attempt = 0; attempt < 3; attempt++) {\n  try { return await client.write(...) } catch (e) {\n    if (isCloudServiceError(e) && e.status >= 500 && attempt < 2) {\n      await new Promise((r) => setTimeout(r, 2 ** attempt * 500)); continue\n    }\n    throw e\n  }\n}","preventionTips":["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"],"tags":["search","http","upstream","cloud-service"],"backgroundTag":"http-error-response","analyzedSha":"5e06e544a296b9033f20f71f11c559f81a0e5739","analyzedAt":"2026-08-27T07:24:39.599Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}