{"record":{"id":"900ce54f7975376c","repo":"danny-avila/LibreChat","slug":"waitforrun-runinfo-status-run-status","errorCode":null,"errorMessage":"[waitForRun] ${runInfo} | status: ${run.status} | timed out after ${timeout} ms","messagePattern":"\\[waitForRun\\] (.+?) \\| status: (.+?) \\| timed out after (.+?) ms","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"api/server/services/Runs/handle.js","lineNumber":165,"sourceCode":"      break;\n    }\n\n    // may use in future; for now, just fetch from the final status\n    await runManager.fetchRunSteps({\n      openai,\n      thread_id: thread_id,\n      run_id: run_id,\n      runStatus: run.status,\n    });\n\n    await sleep(pollIntervalMs);\n    timeElapsed += pollIntervalMs;\n  }\n\n  if (timeElapsed >= timeout) {\n    const timeoutMessage = `[waitForRun] ${runInfo} | status: ${run.status} | timed out after ${timeout} ms`;\n    logger.warn(timeoutMessage);\n    throw new Error(timeoutMessage);\n  }\n\n  return run;\n}\n\n/**\n * Retrieves all steps of a run.\n *\n * @deprecated: Steps are handled with runAssistant now.\n * @param {Object} params - The parameters for the retrieveRunSteps function.\n * @param {OpenAIClient} params.openai - The OpenAI client instance.\n * @param {string} params.thread_id - The ID of the thread associated with the run.\n * @param {string} params.run_id - The ID of the run to retrieve steps for.\n * @return {Promise<RunStep[]>} A promise that resolves to an array of RunStep objects.\n */\nasync function _retrieveRunSteps({ openai, thread_id, run_id }) {\n  const runSteps = await openai.beta.threads.runs.steps.list(run_id, { thread_id });\n  return runSteps;","sourceCodeStart":147,"sourceCodeEnd":183,"githubUrl":"https://github.com/danny-avila/LibreChat/blob/5ff282f9006c436e561de1afd39a481bea1ef0d8/api/server/services/Runs/handle.js#L147-L183","documentation":"Thrown by waitForRun when the outer polling loop accumulates timeElapsed >= timeout (default 60000*3 = 180000 ms) and the run has not left the IN_PROGRESS/QUEUED states. The run is still active upstream but the client gave up waiting; the last-known run status is included in the message.","triggerScenarios":"A long-running assistant run (complex tool use, slow model, heavy file search) exceeding 3 minutes; a run stuck QUEUED due to OpenAI capacity; pollIntervalMs so large the budget is consumed before a state change can be observed.","commonSituations":"Code interpreter or function-calling runs that legitimately take minutes; busy periods on OpenAI; a tight default timeout for demanding workloads.","solutions":["Raise the timeout argument passed to waitForRun for workloads known to run long.","Move the user-facing flow to async/job-based completion so the HTTP request is not blocked by polling.","Check the run status upstream (retrieveRun) after the timeout to confirm whether it eventually completed, and reconcile.","Reduce pollIntervalMs only if it helps detect terminal state sooner without increasing API load."],"exampleFix":"// before\nawait waitForRun({ openai, run_id, thread_id, runManager }); // timeout defaults to 180000\n\n// after\nawait waitForRun({ openai, run_id, thread_id, runManager, timeout: 10 * 60 * 1000 });","handlingStrategy":"retry","validationCode":"const timeout = isLongRunningAgent ? 10 * 60 * 1000 : 3 * 60 * 1000;\nawait waitForRun({ openai, run_id, thread_id, runManager, timeout });","typeGuard":null,"tryCatchPattern":"try {\n  await waitForRun({ openai, run_id, thread_id, runManager, timeout });\n} catch (err) {\n  if (err.message.includes('timed out after')) {\n    // reconcile: poll retrieveRun once more to see if it finished\n    return { status: 'timeout', run_id, thread_id };\n  }\n  throw err;\n}","preventionTips":["Pass an explicit timeout sized to the workload.","Move long-running runs to an async/job model so polling does not block callers.","After a timeout, reconcile upstream to capture a late completion."],"tags":["openai","assistants","timeout","polling"],"backgroundTag":null,"analyzedSha":"5ff282f9006c436e561de1afd39a481bea1ef0d8","analyzedAt":"2026-08-12T21:38:08.145Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}