{"record":{"id":"de9c9c457131c745","repo":"can1357/oh-my-pi","slug":"finaltext","errorCode":null,"errorMessage":"${finalText}","messagePattern":"\\$\\{finalText\\}","errorType":"exception","errorClass":"ToolError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tools/bash.ts","lineNumber":863,"sourceCode":"\t\t\t\t\t\tonMinimizedSave: originalText => saveBashOriginalArtifact(this.session, originalText),\n\t\t\t\t\t});\n\t\t\t\t\tconst wallTimeMs = performance.now() - wallTimeStart;\n\t\t\t\t\tconst finalResult = await this.#buildCompletedResult(result, options.timeoutSec, {\n\t\t\t\t\t\trequestedTimeoutSec: options.requestedTimeoutSec,\n\t\t\t\t\t\tnotices: options.notices ?? [],\n\t\t\t\t\t\twallTimeMs,\n\t\t\t\t\t});\n\t\t\t\t\tconst finalText = this.#extractTextResult(finalResult);\n\t\t\t\t\tlatestText = finalText;\n\t\t\t\t\t// Hand the detailed result to the foreground auto-background\n\t\t\t\t\t// waiter (which renders it, footer included) before deciding\n\t\t\t\t\t// the job's terminal state.\n\t\t\t\t\tcompletion.resolve({ kind: \"completed\", result: finalResult });\n\t\t\t\t\tif (finalResult.isError === true) {\n\t\t\t\t\t\t// A non-zero exit is a completed command that failed. Re-enter\n\t\t\t\t\t\t// the failure path so the job manager records it as failed and\n\t\t\t\t\t\t// delivers the error text, matching prior throw-based behavior.\n\t\t\t\t\t\tthrow new ToolError(finalText);\n\t\t\t\t\t}\n\t\t\t\t\tawait reportProgress(finalText, { async: { state: \"completed\", jobId, type: \"bash\" } });\n\t\t\t\t\treturn finalText;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\t\tlatestText = message;\n\t\t\t\t\tcompletion.resolve({ kind: \"failed\", error });\n\t\t\t\t\tawait reportProgress(message, { async: { state: \"failed\", jobId, type: \"bash\" } });\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\townerId: this.session.getAgentId?.() ?? undefined,\n\t\t\t\tonProgress: async text => {\n\t\t\t\t\tlatestText = text;\n\t\t\t\t\tif (!forwardUpdates) return;\n\t\t\t\t\tawait options.onUpdate?.({\n\t\t\t\t\t\tcontent: [{ type: \"text\", text }],","sourceCodeStart":845,"sourceCodeEnd":881,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/bash.ts#L845-L881","documentation":"When a backgrounded bash job finishes with isError=true (typically a non-zero exit code), the job's runner re-throws the command's final output text as a ToolError. This re-enters the failure path so the AsyncJobManager records the job as failed and delivers the error text, matching the behavior of foreground execution. The message content is the command's own captured output, not a library diagnostic.","triggerScenarios":"Running any command in async/auto-background mode whose process exits with a non-zero status (e.g. `npm test` failing, `grep` finding no match, a build error).","commonSituations":"Failing test suites or builds left running in the background; commands like `diff`/`grep` that use exit codes as signals; scripts whose last statement returns non-zero.","solutions":["Read the error text: it is the command's real output; fix whatever the command reported.","If the exit code is meaningful-but-not-failure (grep, diff, test harnesses), append `|| true` or inspect exit codes explicitly in the script.","Check the job's output artifact for full logs when the tail text is truncated."],"exampleFix":"// before: background command fails on grep no-match\nawait bash.execute(id, { command: \"grep TODO src/\", async: true });\n\n// after: treat no-match as success\nawait bash.execute(id, { command: \"grep TODO src/ || true\", async: true });","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await bash.execute(id, { command, async: true });\n} catch (e) {\n  if (e instanceof ToolError) {\n    // message is the command's own output; log/inspect it as command failure\n    logger.warn(\"background command failed\", { output: e.message });\n  } else throw e;\n}","preventionTips":["Design background commands to exit 0 (append `|| true` for signal-style exit codes).","Capture the job's output artifact for full logs, not just the tail.","Test background commands in the foreground first to confirm exit behavior."],"tags":["exit-code","command-failed","bash"],"backgroundTag":"nonzero-exit-code","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}