{"record":{"id":"a4ba82ede1514534","repo":"can1357/oh-my-pi","slug":"no-isolation-backend-is-available","errorCode":null,"errorMessage":"No isolation backend is available.","messagePattern":"No isolation backend is available\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/task/worktree.ts","lineNumber":545,"sourceCode":"\t\t\t// frozen repo that still borrows the source object DB via alternates.\n\t\t\tawait vcs.detachGitDir(mergedDir, sourceCommonDir);\n\t\t\treturn {\n\t\t\t\tmergedDir,\n\t\t\t\tbackend: candidate,\n\t\t\t\tfellBack: candidate !== resolution.kind || resolution.fellBack,\n\t\t\t\tfallbackReason,\n\t\t\t};\n\t\t} catch (err) {\n\t\t\tawait fs.rm(baseDir, { recursive: true, force: true });\n\t\t\tconst message = errorMessage(err);\n\t\t\tif (!natives.isoIsUnavailableError(message)) {\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t\tfallbackReason ??= message;\n\t\t}\n\t}\n\n\tthrow new Error(fallbackReason ?? \"No isolation backend is available.\");\n}\n\n/** Tear down a handle returned by {@link ensureIsolation}. */\nexport async function cleanupIsolation(handle: IsolationHandle): Promise<void> {\n\ttry {\n\t\ttry {\n\t\t\tawait natives.isoStop(handle.backend, handle.mergedDir);\n\t\t} catch (err) {\n\t\t\tlogger.warn(\"isolation backend stop failed during cleanup\", {\n\t\t\t\tbackend: handle.backend,\n\t\t\t\tmergedDir: handle.mergedDir,\n\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t});\n\t\t}\n\t} finally {\n\t\t// baseDir is the parent of the merged directory\n\t\tconst baseDir = path.dirname(handle.mergedDir);\n\t\tawait fs.rm(baseDir, { recursive: true, force: true });","sourceCodeStart":527,"sourceCodeEnd":563,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/task/worktree.ts#L527-L563","documentation":"ensureIsolation tries each available isolation backend (e.g. git worktree, fallbacks) in order; each failure's message is recorded as fallbackReason. If every backend fails — or none is compiled/available — it throws with the last failure reason, or the generic message when no reason was captured.","triggerScenarios":"Calling ensureIsolation (directly or via runIsolatedSubprocess/handle) when no backend attempt succeeded and fallbackReason was never set — i.e. zero backends were available to try in the current environment.","commonSituations":"Running in a workspace with no Git repo and no other isolation backend; stripped-down builds or environments where backend detection finds nothing; all backends failed with errors that were rethrown rather than recorded.","solutions":["Ensure the workspace is a valid Git repository so the worktree backend is available","Read any preceding log/fallback messages for the underlying per-backend failure","Disable isolation via `task.isolation.mode: none` if isolation is not required"],"exampleFix":"// before: subagent task in non-git dir\n$ omp  // -> No isolation backend is available.\n// after\n$ git init && omp","handlingStrategy":"try-catch","validationCode":"// check a worktree-capable git repo exists before requesting isolation\nconst root = await getRepoRoot(cwd); // throws early with a specific reason if not","typeGuard":null,"tryCatchPattern":"let handle: IsolationHandle | null = null;\ntry {\n\thandle = await ensureIsolation(opts);\n} catch (err) {\n\tlogger.warn(\"Isolation unavailable, running in-place\", { reason: (err as Error).message });\n\treturn runInPlace(opts);\n}","preventionTips":["Keep the workspace a valid git repo so the worktree backend is always available","Read fallbackReason messages in logs to know which backend failed and why","Set task.isolation.mode explicitly rather than relying on auto-detection"],"tags":["isolation","git","sandboxing"],"backgroundTag":"no-isolation-backend","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}