{"record":{"id":"fd4519db13537b33","repo":"headroomlabs-ai/headroom","slug":"openai-api-key-is-required-for-openai-embedder","errorCode":null,"errorMessage":"openai_api_key is required for OpenAI embedder","messagePattern":"openai_api_key is required for OpenAI embedder","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"headroom/memory/factory.py","lineNumber":169,"sourceCode":"    sentence-transformers / ONNX model-load cost more than once.\n\n    Args:\n        config: Memory system configuration.\n\n    Returns:\n        An Embedder implementation based on config.embedder_backend.\n\n    Raises:\n        ValueError: If the embedder backend is not supported.\n    \"\"\"\n\n    # Validate inputs ahead of the cache. The cache key is\n    # ``(backend, model)`` and intentionally does NOT include the API\n    # key — but that means a cached OpenAI embedder would shadow the\n    # config-validation step for a subsequent caller who forgot to pass\n    # ``openai_api_key``. Run the validation up front instead.\n    if config.embedder_backend == EmbedderBackend.OPENAI and not config.openai_api_key:\n        raise ValueError(\"openai_api_key is required for OpenAI embedder\")\n\n    key = (\n        config.embedder_backend.value\n        if hasattr(config.embedder_backend, \"value\")\n        else str(config.embedder_backend),\n        config.embedder_model or \"\",\n        # The Ollama backend is built with ``base_url=config.ollama_base_url``,\n        # so two configs that share a backend and model but point at different\n        # Ollama servers must NOT share a cached embedder — otherwise the second\n        # caller silently gets an embedder bound to the first server. (The\n        # ``openai_api_key`` omission is handled by the up-front validation\n        # above; ``ollama_base_url`` has no such guard and would just resolve to\n        # the wrong host.)\n        config.ollama_base_url or \"\",\n    )\n\n    with _EMBEDDER_CACHE_LOCK:\n        cached = _EMBEDDER_CACHE.get(key)","sourceCodeStart":151,"sourceCodeEnd":187,"githubUrl":"https://github.com/headroomlabs-ai/headroom/blob/322425c43bffde1ed0b64fecf3cf5951565dd82b/headroom/memory/factory.py#L151-L187","documentation":"Choosing the OpenAI embedder requires an API key, and the factory validates this BEFORE consulting the process-wide embedder cache (the cache key is (backend, model) and omits the key, so a cached instance could otherwise mask a missing key for a later caller). ValueError is raised when config.embedder_backend is OPENAI and config.openai_api_key is falsy.","triggerScenarios":"MemoryConfig(embedder_backend=EmbedderBackend.OPENAI) with openai_api_key unset/None/empty, passed to create_memory_system; or the OPENAI_API_KEY env var was expected but never read (the config field does not auto-populate from env in this path).","commonSituations":"Dev machine has OPENAI_API_KEY exported but the config object was built without it; key set in a .env file that was never loaded; CI secret missing; key string accidentally whitespace-empty.","solutions":["Pass the key explicitly: MemoryConfig(embedder_backend=EmbedderBackend.OPENAI, embedder_model=\"text-embedding-3-small\", openai_api_key=os.environ[\"OPENAI_API_KEY\"])","Confirm the env var is actually visible to the process (print(bool(os.environ.get('OPENAI_API_KEY')))) — it is not picked up implicitly","If you intended local embeddings, use EmbedderBackend.SENTENCE_TRANSFORMERS or OLLAMA instead of OPENAI"],"exampleFix":"# before\nconfig = MemoryConfig(embedder_backend=EmbedderBackend.OPENAI)\n\n# after\nimport os\nconfig = MemoryConfig(\n    embedder_backend=EmbedderBackend.OPENAI,\n    openai_api_key=os.environ[\"OPENAI_API_KEY\"],\n)","handlingStrategy":"validation","validationCode":"if config.embedder_backend == EmbedderBackend.OPENAI and not config.openai_api_key:\n    raise RuntimeError(\"OPENAI_API_KEY not set; cannot use OpenAI embedder\")\nsystem = await create_memory_system(config)","typeGuard":"def openai_embedder_ready(cfg: MemoryConfig) -> bool:\n    return cfg.embedder_backend != EmbedderBackend.OPENAI or bool(cfg.openai_api_key)","tryCatchPattern":"try:\n    system = await create_memory_system(config)\nexcept ValueError as e:\n    if \"openai_api_key is required\" in str(e):\n        fail_startup(\"missing OpenAI key for embedder\")\n    raise","preventionTips":["Centralize key resolution: pull os.environ['OPENAI_API_KEY'] in one config builder","Add a startup preflight that checks each configured backend's required secrets","Note the embedder cache is keyed by (backend, model) only — validation cannot be skipped for later callers either"],"tags":["memory","embeddings","openai","credentials","configuration"],"backgroundTag":null,"analyzedSha":"322425c43bffde1ed0b64fecf3cf5951565dd82b","analyzedAt":"2026-08-15T01:03:05.481Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}