{"record":{"id":"a3a19b0d8bad47af","repo":"headroomlabs-ai/headroom","slug":"openai-api-error-e","errorCode":null,"errorMessage":"OpenAI API error: {e}","messagePattern":"OpenAI API error: (.+?)","errorType":"exception","errorClass":"ConnectionError","httpStatus":null,"severity":"error","filePath":"headroom/memory/adapters/embedders.py","lineNumber":699,"sourceCode":"                    model=self._model_name,\n                    input=texts,\n                )\n                # Extract embeddings in order\n                embeddings = [np.array(item.embedding, dtype=np.float32) for item in response.data]\n                return embeddings\n\n            except (APIConnectionError, APITimeoutError, RateLimitError) as e:\n                last_error = e\n                delay = self.RETRY_DELAY_BASE * (2**attempt)\n                logger.warning(\n                    f\"OpenAI API error (attempt {attempt + 1}/{self._max_retries}): {e}. \"\n                    f\"Retrying in {delay:.1f}s...\"\n                )\n                await asyncio.sleep(delay)\n\n            except Exception as e:\n                # Non-retryable error\n                raise ConnectionError(f\"OpenAI API error: {e}\") from e\n\n        # All retries exhausted\n        raise ConnectionError(\n            f\"OpenAI API failed after {self._max_retries} retries: {last_error}\"\n        ) from last_error\n\n    async def embed(self, text: str) -> np.ndarray:\n        \"\"\"Generate an embedding for a single text.\n\n        Args:\n            text: The text to embed.\n\n        Returns:\n            Normalized embedding vector as float32 numpy array.\n\n        Raises:\n            ConnectionError: If API call fails after retries.\n        \"\"\"","sourceCodeStart":681,"sourceCodeEnd":717,"githubUrl":"https://github.com/headroomlabs-ai/headroom/blob/322425c43bffde1ed0b64fecf3cf5951565dd82b/headroom/memory/adapters/embedders.py#L681-L717","documentation":"Inside OpenAIEmbedder._embed_with_retry's retry loop, transient errors (APIConnectionError, APITimeoutError, RateLimitError) are retried with exponential backoff, but any other exception hits this branch and is immediately wrapped in ConnectionError('OpenAI API error: {e}') with the original chained. It means a non-retryable client- or request-level failure: bad request, authentication, invalid model, content filter, etc.","triggerScenarios":"Calling embed()/embed_batch() when the OpenAI API returns 400/401/403/404/422 — e.g. unknown embedding model name, wrong API key permissions, input text exceeding token limits, or filtered content. Anything not classified as connection/timeout/rate-limit lands here on the first attempt.","commonSituations":"Model name typo like 'text-embedding-3-large ' (trailing space) or a deprecated model after OpenAI sunsets it; org without access to the embedding model; a single oversized document in a batch; key valid but from a project with restricted endpoints.","solutions":["Read the chained original exception (__cause__) — it carries the HTTP status and OpenAI error message that names the real problem.","Fix the model name: stick to text-embedding-3-small / text-embedding-3-large unless the account supports others.","Chunk or truncate very long inputs before embedding; check per-item token counts.","Verify the API key's project/org has embedding access; test with curl if unsure.","Do NOT retry this error class — it is non-retryable by design."],"exampleFix":"# before\nawait embedder.embed(huge_doc)  # ConnectionError: OpenAI API error: ... maximum context length ...\n\n# after\ntext = huge_doc[:8000]  # chunk/truncate to model token limit\nawait embedder.embed(text)","handlingStrategy":"try-catch","validationCode":"MAX_TOKENS = 8191  # text-embedding-3-small per-request limit\n\ndef embeddable(text: str) -> bool:\n    \"\"\"Cheap pre-check: non-empty and under the model token ceiling.\"\"\"\n    return bool(text.strip()) and len(text) // 4 < MAX_TOKENS  # ~4 chars/token heuristic","typeGuard":null,"tryCatchPattern":"try:\n    vec = await embedder.embed(text)\nexcept ConnectionError as e:\n    if \"OpenAI API error\" in str(e) and not isinstance(e.__cause__, tuple(map(type, ()) )):\n        pass\n# simpler and explicit:\ntry:\n    vec = await embedder.embed(text)\nexcept ConnectionError as e:\n    cause = e.__cause__\n    if type(cause).__name__ in {\"BadRequestError\", \"AuthenticationError\", \"NotFoundError\", \"PermissionDeniedError\"}:\n        log.error(\"non-retryable: %s\", cause); raise\n    raise","preventionTips":["Inspect e.__cause__ — the OpenAI SDK exception carries the HTTP status and message.","Chunk long inputs to the model token limit before embedding.","Confirm the model name exists for your account before batch jobs."],"tags":["api","openai","embeddings","non-retryable","network"],"backgroundTag":null,"analyzedSha":"322425c43bffde1ed0b64fecf3cf5951565dd82b","analyzedAt":"2026-08-15T01:03:05.481Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}