{"record":{"id":"85db144e9e095b7e","repo":"different-ai/openwork","slug":"openai-api-key-required-for-computer-use","errorCode":null,"errorMessage":"OpenAI API key required for computer use.","messagePattern":"OpenAI API key required for computer use\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/handsfree/src/cua-runner.mjs","lineNumber":13,"sourceCode":"export const CUA_DEFAULT_MODEL = \"gpt-5.5\";\nexport const CUA_MAX_TURNS = 30;\n\nexport async function runCuaLoop({\n  task,\n  apiKey,\n  callTool,\n  onProgress,\n  signal,\n  model = CUA_DEFAULT_MODEL,\n  maxTurns = CUA_MAX_TURNS,\n}) {\n  if (!apiKey?.trim()) throw new Error(\"OpenAI API key required for computer use.\");\n  if (typeof callTool !== \"function\") throw new Error(\"callTool is required.\");\n\n  const display = await callTool(\"display_info\", {});\n  const displayInfo = parseToolText(display) ?? { width: 1440, height: 900 };\n  onProgress?.({ kind: \"start\", width: displayInfo.width, height: displayInfo.height });\n\n  const items = [{ role: \"user\", content: String(task ?? \"\") }];\n  const messages = [];\n\n  for (let turn = 0; turn < maxTurns; turn += 1) {\n    if (signal?.aborted) return { ok: true, messages, turns: turn, aborted: true };\n    onProgress?.({ kind: \"turn\", turn: turn + 1 });\n\n    const response = await fetch(\"https://api.openai.com/v1/responses\", {\n      method: \"POST\",\n      headers: { Authorization: `Bearer ${apiKey}`, \"Content-Type\": \"application/json\" },\n      body: JSON.stringify({ model, input: items, tools: [{ type: \"computer\" }] }),\n      signal,","sourceCodeStart":1,"sourceCodeEnd":31,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/packages/handsfree/src/cua-runner.mjs#L1-L31","documentation":"runCuaLoop drives an OpenAI computer-use agent loop (screenshot → model → action). It refuses to start when the apiKey argument is missing, empty, or whitespace-only, because every turn calls the OpenAI Responses API which requires bearer credentials. The check is a fail-fast guard before any tool calls or network requests are made.","triggerScenarios":"Calling runCuaLoop without passing apiKey, with apiKey: process.env.OPENAI_API_KEY when that env var is unset, or with an empty/whitespace string (\"\"). Any callTool implementation will not be invoked — the throw happens first.","commonSituations":"Deployed environment (CI, server, sandboxed app) where OPENAI_API_KEY was never set or was stripped by the .env loader; key renamed to a vendor-specific var (e.g. using an OpenWork/BYOK gateway variable) while the runner still expects OPENAI_API_KEY; apiKey passed via a config object where the field is optional and silently undefined.","solutions":["Set OPENAI_API_KEY in the environment or .env file the runner process actually loads, then verify with `echo ${OPENAI_API_KEY:+set}`.","Pass apiKey explicitly: runCuaLoop({ apiKey: <resolved key>, callTool, ... }) instead of relying on ambient env resolution.","Validate the key before starting the loop: `if (!apiKey?.trim()) throw ...` mirrors the library check, so add your own preflight with a clearer message.","If using a proxy/gateway that injects auth, wrap callTool so the key requirement is satisfied or patch the options to forward the gateway token as apiKey."],"exampleFix":"// before\nawait runCuaLoop({ callTool, onProgress })\n// after\nawait runCuaLoop({ apiKey: process.env.OPENAI_API_KEY!, callTool, onProgress })","handlingStrategy":"validation","validationCode":"const apiKey = process.env.OPENAI_API_KEY;\nif (!apiKey || !apiKey.trim()) throw new Error(\"Set OPENAI_API_KEY before running the CUA loop\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Load and assert env vars at process startup, not at call time","Add a startup preflight that checks required keys per feature (computer use, embeddings, etc.)","Keep one canonical key name per provider and document it"],"tags":["missing-api-key","configuration","openai","computer-use"],"backgroundTag":"missing-env-var","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}