{"record":{"id":"591bd865338fdb65","repo":"can1357/oh-my-pi","slug":"unhandled-rejection-missing-await-messages-j","errorCode":null,"errorMessage":"Unhandled rejection (missing await?): ${messages.join(\"\\n[unhandled rejection] \")}","messagePattern":"Unhandled rejection \\(missing await\\?\\): (.+?)","errorType":"exception","errorClass":"ToolError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tools/browser/cmux/cmux-tab.ts","lineNumber":1513,"sourceCode":"\t\t} catch (error) {\n\t\t\trunFailed = true;\n\t\t\trunError = error;\n\t\t}\n\t\trunAc.abort(runEndedError);\n\t\t// Let rejection callbacks run while this run can still own guest-created promises.\n\t\tawait Bun.sleep(0);\n\t\tif (hasFloatingFailure && !runFailed) await floatingFailure;\n\t\tif (runFailed) {\n\t\t\tfor (const reason of activeRun.floatingRejections) {\n\t\t\t\tlogger.warn(\"Unhandled rejection accompanied a failed cmux browser run\", { filename, error: reason });\n\t\t\t}\n\t\t\tthrow runError;\n\t\t}\n\t\tif (activeRun.floatingRejections.length > 0) {\n\t\t\tconst messages = activeRun.floatingRejections.map(reason =>\n\t\t\t\treason instanceof Error ? reason.message : String(reason),\n\t\t\t);\n\t\t\tthrow new ToolError(`Unhandled rejection (missing await?): ${messages.join(\"\\n[unhandled rejection] \")}`, {\n\t\t\t\trejections: activeRun.floatingRejections,\n\t\t\t});\n\t\t}\n\t\treturn { displays: output.finish(), returnValue: cloneSafe(returnValue), screenshots };\n\t} finally {\n\t\trunActive = false;\n\t\tuninstallRejectionInterceptor();\n\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t\trunAc.abort(runEndedError);\n\t\tactiveCmuxRuns.delete(filename);\n\t\trememberCmuxRunFile(filename);\n\t\ttab.clearRunContext();\n\t}\n}\n\nfunction numberFrom(value: unknown, fallback: number): number {\n\treturn typeof value === \"number\" && Number.isFinite(value) ? value : fallback;\n}","sourceCodeStart":1495,"sourceCodeEnd":1531,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/browser/cmux/cmux-tab.ts#L1495-L1531","documentation":"The run runner collects promises that rejected without being awaited (`floatingRejections`) via facade wrappers. After the run body completes, if any remain, it throws this ToolError joining them with \"[unhandled rejection]\" prefixes. It surfaces fire-and-forget async failures that would otherwise be silently lost (the message hints the typical cause: missing await).","triggerScenarios":"Calling an async tab/page/browser method inside the run without `await` (navigation, evaluate, waitFor) whose promise later rejects; attaching .then without .catch; scheduling async work the run doesn't track.","commonSituations":"Refactors that dropped an await; intentionally fire-and-forget calls that fail (timeout, navigation error); Promise.all replaced by sequential statements where one call was left unawaited.","solutions":["Await every async browser call inside the run body — the first listed rejection message identifies the failing call.","If genuinely fire-and-forget, attach a .catch() that records the failure via the run's failure recorder.","Use the run's signal/abort handling so abandoned work is cancelled rather than rejecting unobserved."],"exampleFix":"// before\ntab.click('#submit');\nawait tab.waitFor('.success');\n// after\nawait tab.click('#submit'); // was rejecting unobserved\nawait tab.waitFor('.success');","handlingStrategy":"try-catch","validationCode":"// lint/enforce: every promise-returning browser call in a run must be awaited\nconst results = await Promise.all([tab.click('#a'), tab.click('#b')]); // never bare calls","typeGuard":null,"tryCatchPattern":"try {\n  await runBody();\n} catch (err) {\n  if (String(err.message).startsWith('Unhandled rejection (missing await?)')) {\n    const causes = String(err.message).split('[unhandled rejection] ').slice(1);\n    console.error('unawaited browser calls failed:', causes);\n  }\n  throw err;\n}","preventionTips":["Enable lint rules (no-floating-promises) for run-body code.","Await every async tab/page/browser call; if intentionally detached, attach .catch that records the failure.","After refactors, grep run bodies for bare `tab.` / `page.` calls missing await."],"tags":["unhandled-rejection","async","missing-await","browser-automation"],"backgroundTag":"unhandled-promise-rejection","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}