{"record":{"id":"23e5cfc50b184dbf","repo":"can1357/oh-my-pi","slug":"async-job-manager-unavailable-for-this-session","errorCode":null,"errorMessage":"Async job manager unavailable for this session.","messagePattern":"Async job manager unavailable for this session\\.","errorType":"exception","errorClass":"ToolError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tools/bash.ts","lineNumber":1013,"sourceCode":"\t\t\tthrow new ToolError(`Working directory is not a directory: ${commandCwd}`);\n\t\t}\n\n\t\t// A timeout of 0 is an explicit long-running-command contract: the user\n\t\t// must still cancel the call or job, but OMP does not impose a deadline.\n\t\tconst requestedTimeoutSec = rawTimeout;\n\t\tconst timeoutDisabled = requestedTimeoutSec === 0;\n\t\tconst maxTimeout = this.session.settings.get(\"tools.maxTimeout\");\n\t\tconst timeoutSec = timeoutDisabled ? undefined : clampTimeout(\"bash\", requestedTimeoutSec, maxTimeout);\n\t\tconst timeoutMs = timeoutSec === undefined ? undefined : timeoutSec * 1000;\n\t\tconst pendingNotices: string[] = [];\n\t\tif (timeoutSec !== undefined) {\n\t\t\tconst timeoutClampNotice = formatTimeoutClampNotice(requestedTimeoutSec, timeoutSec, maxTimeout);\n\t\t\tif (timeoutClampNotice) pendingNotices.push(timeoutClampNotice);\n\t\t}\n\n\t\tif (asyncRequested) {\n\t\t\tif (!this.session.asyncJobManager) {\n\t\t\t\tthrow new ToolError(\"Async job manager unavailable for this session.\");\n\t\t\t}\n\t\t\tconst job = this.#startManagedBashJob({\n\t\t\t\tcommand,\n\t\t\t\tcommandCwd,\n\t\t\t\ttimeoutMs,\n\t\t\t\ttimeoutSec,\n\t\t\t\trequestedTimeoutSec,\n\t\t\t\tnotices: pendingNotices,\n\n\t\t\t\tresolvedEnv,\n\t\t\t\tonUpdate,\n\t\t\t\tforwardUpdates: false,\n\t\t\t});\n\t\t\treturn this.#buildBackgroundStartResult(job.jobId, \"\", timeoutSec, {\n\t\t\t\trequestedTimeoutSec,\n\t\t\t\tnotices: pendingNotices,\n\t\t\t});\n\t\t}","sourceCodeStart":995,"sourceCodeEnd":1031,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/bash.ts#L995-L1031","documentation":"When the caller explicitly requests async=true, the tool requires session.asyncJobManager to register the background job, deliver progress, and support later job-control calls. If the manager is absent the request cannot be honored and the tool throws immediately, before #startManagedBashJob runs. This is the explicit-async counterpart of the same guard inside #startManagedBashJob.","triggerScenarios":"bash tool call with async=true on a session whose asyncJobManager was never attached (minimal SDK session, alternative host, or a session type without background-job support).","commonSituations":"Embedding the coding agent in an app with a hand-rolled session object; running the tool against a session created by an older integration layer; test harnesses stubbing the session incompletely.","solutions":["Attach an AsyncJobManager to the session (session.asyncJobManager = new AsyncJobManager()) before making async bash calls.","Run the command synchronously (omit async) if the host cannot support job management.","Gate the feature in your embedding layer: check session.asyncJobManager first and disable background prompts when it's missing."],"exampleFix":"// before: stub session missing the manager\nconst session = baseSession; // asyncJobManager: undefined\nawait bash.execute(id, { command: \"make all\", async: true });\n\n// after: supply the manager or run foreground\nsession.asyncJobManager = new AsyncJobManager();\nawait bash.execute(id, { command: \"make all\", async: true });","handlingStrategy":"validation","validationCode":"if (asyncRequested && !session.asyncJobManager) {\n  asyncRequested = false; // degrade to foreground, or surface a config error\n}\nawait bash.execute(id, { command, async: asyncRequested });","typeGuard":null,"tryCatchPattern":"try {\n  await bash.execute(id, { command, async: true });\n} catch (e) {\n  if (e instanceof ToolError && e.message.includes(\"job manager unavailable\")) {\n    return bash.execute(id, { command });\n  }\n  throw e;\n}","preventionTips":["Wire AsyncJobManager into every session your host creates.","Feature-detect session.asyncJobManager before exposing async bash to the model.","Cover session construction in tests so the manager is never silently missing."],"tags":["background-jobs","session-config","async"],"backgroundTag":"job-manager-unavailable","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}