{"record":{"id":"4c5fb991191b966b","repo":"ruvnet/ruflo","slug":"authentication-4c5fb9","errorCode":"AUTHENTICATION","errorMessage":"OpenAI API key is required","messagePattern":"OpenAI API key is required","errorType":"exception","errorClass":"AuthenticationError","httpStatus":401,"severity":"error","filePath":"v3/@claude-flow/providers/src/openai-provider.ts","lineNumber":180,"sourceCode":"      },\n      'o3-mini': {\n        promptCostPer1k: 0.0011,\n        completionCostPer1k: 0.0044,\n        currency: 'USD',\n      },\n    },\n  };\n\n  private baseUrl: string = 'https://api.openai.com/v1';\n  private headers: Record<string, string> = {};\n\n  constructor(options: BaseProviderOptions) {\n    super(options);\n  }\n\n  protected async doInitialize(): Promise<void> {\n    if (!this.config.apiKey) {\n      throw new AuthenticationError('OpenAI API key is required', 'openai');\n    }\n\n    this.baseUrl = this.config.apiUrl || 'https://api.openai.com/v1';\n    this.headers = {\n      Authorization: `Bearer ${this.config.apiKey}`,\n      'Content-Type': 'application/json',\n    };\n\n    if (this.config.providerOptions?.organization) {\n      this.headers['OpenAI-Organization'] = this.config.providerOptions.organization as string;\n    }\n  }\n\n  protected async doComplete(request: LLMRequest): Promise<LLMResponse> {\n    const openAIRequest = this.buildRequest(request);\n\n    const controller = new AbortController();\n    const timeout = setTimeout(() => controller.abort(), this.config.timeout || 60000);","sourceCodeStart":162,"sourceCodeEnd":198,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/providers/src/openai-provider.ts#L162-L198","documentation":"OpenAIProvider.doInitialize() runs during provider.initialize(); if config.apiKey is falsy it throws AuthenticationError before any HTTP call. The key becomes the Authorization: Bearer header against https://api.openai.com/v1 (or config.apiUrl), and providerOptions.organization optionally sets the OpenAI-Organization header.","triggerScenarios":"new OpenAIProvider({ name: 'openai', config: { model: 'gpt-4o' } }) with no apiKey, or apiKey: process.env.OPENAI_API_KEY when the variable is unset in that runtime.","commonSituations":"OPENAI_API_KEY missing in CI/CD or Docker (secret not mounted); .env file present but not loaded (missing --env-file / dotenv import); key named OPENAI_KEY instead of OPENAI_API_KEY.","solutions":["Pass the key explicitly: config: { apiKey: process.env.OPENAI_API_KEY, model: 'gpt-4o' }","Verify the env var in the actual runtime: printenv OPENAI_API_KEY (or docker exec ... printenv)","Load .env before constructing the provider (import 'dotenv/config' or node --env-file=.env)","Add a startup check that fails with a clear message when required keys are absent"],"exampleFix":"// before\n// node app.js  (no dotenv loaded)\nconst provider = new OpenAIProvider({\n  name: 'openai',\n  config: { model: 'gpt-4o' }, // apiKey undefined -> AuthenticationError at initialize()\n});\n\n// after\n// node --env-file=.env app.js\nconst provider = new OpenAIProvider({\n  name: 'openai',\n  config: { apiKey: process.env.OPENAI_API_KEY!, model: 'gpt-4o' },\n});","handlingStrategy":"validation","validationCode":"const apiKey = process.env.OPENAI_API_KEY;\nif (!apiKey) {\n  throw new Error('OPENAI_API_KEY is not set - cannot create openai provider');\n}\nconst provider = new OpenAIProvider({ name: 'openai', config: { apiKey, model: 'gpt-4o' } });","typeGuard":"import { AuthenticationError } from './types.js';\nfunction isAuthError(e: unknown): e is AuthenticationError {\n  return e instanceof AuthenticationError;\n}","tryCatchPattern":"try {\n  await provider.initialize();\n} catch (e) {\n  if (e instanceof AuthenticationError) {\n    throw new Error(`openai credentials missing or invalid: ${e.message}`); // config bug - no retry\n  }\n  throw e;\n}","preventionTips":["Load .env explicitly (node --env-file=.env or import 'dotenv/config') before building providers","Assert required env vars in a startup validator that names the variable","Mount Docker/Kubernetes secrets and verify with printenv inside the container"],"tags":["authentication","config","env-var","openai","initialization"],"backgroundTag":"missing-api-key","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}