{"record":{"id":"78f25e2c586a8be2","repo":"can1357/oh-my-pi","slug":"failed-to-restore-workspace-after-failed-switch-to","errorCode":null,"errorMessage":"Failed to restore workspace after failed switch to ${newCwd}: ${restoreError instanceof Error ? restoreError.message : String(restoreError)} (workspace may be inconsistent at ${actual})","messagePattern":"Failed to restore workspace after failed switch to (.+?): (.+?) \\(workspace may be inconsistent at (.+?)\\)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"packages/coding-agent/src/modes/interactive-mode.ts","lineNumber":1629,"sourceCode":"\t\t\t\tawait this.refreshSlashCommandState(previousCwd);\n\t\t\t} catch (restoreError) {\n\t\t\t\tconst actual = this.sessionManager.getCwd();\n\t\t\t\ttry {\n\t\t\t\t\tsetProjectDir(actual);\n\t\t\t\t\tif (isSettingsInitialized()) {\n\t\t\t\t\t\tawait settings.reloadForCwd(actual);\n\t\t\t\t\t\tapplyProviderGlobalsFromSettings(settings);\n\t\t\t\t\t}\n\t\t\t\t\tclearClaudePluginRootsCache();\n\t\t\t\t\tawait this.refreshTitleSystemPrompt(actual);\n\t\t\t\t\tresetCapabilities();\n\t\t\t\t\tawait this.refreshSkillState();\n\t\t\t\t\tawait this.refreshSlashCommandState(actual);\n\t\t\t\t} catch {}\n\t\t\t\tthis.showError(\n\t\t\t\t\t`Failed to switch to ${newCwd} (${error instanceof Error ? error.message : String(error)}), and restoring the previous workspace failed: ${restoreError instanceof Error ? restoreError.message : String(restoreError)}`,\n\t\t\t\t);\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Failed to restore workspace after failed switch to ${newCwd}: ${restoreError instanceof Error ? restoreError.message : String(restoreError)} (workspace may be inconsistent at ${actual})`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthis.showError(\n\t\t\t\t`Cannot change working directory to ${newCwd}: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t\treturn false;\n\t\t}\n\t\tsetSessionTerminalTitle(this.sessionManager.getSessionName(), this.sessionManager.getCwd());\n\t\tthis.statusLine.applyCwdChange();\n\t\treturn true;\n\t}\n\n\tasync getUserInput(): Promise<SubmittedUserInput> {\n\t\tif (this.session.getGoalModeState()?.mode === \"exiting\") {\n\t\t\tawait this.#exitGoalMode({ reason: \"completed\", silent: true });\n\t\t}\n\t\tconst { promise, resolve } = Promise.withResolvers<SubmittedUserInput>();","sourceCodeStart":1611,"sourceCodeEnd":1647,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/modes/interactive-mode.ts#L1611-L1647","documentation":"When a cwd switch fails, InteractiveMode tries to restore the previous workspace; if that restore also fails, it throws this error because the session's working-directory state may now be inconsistent. The user-visible message is shown via showError and the error propagates so callers know state is unreliable.","triggerScenarios":"Calling the change-directory flow (e.g. /cd command) where the switch to newCwd throws, and the subsequent restore of the previous cwd (chdir back, re-init workspace, refresh skill/slash state) also throws — with `actual` being the cwd the process ended up in.","commonSituations":"Both the target directory and the original directory became inaccessible (network mount dropped, permissions changed, directory deleted); watcher or git-workspace re-init failing during rollback on a stale path.","solutions":["Manually chdir/verify the process cwd (shown in the error as `actual`) and correct it — e.g. run /cd again to a valid directory or restart the session","Check both newCwd and the original directory exist and are accessible (permissions, mount health)","Look at the restoreError detail in the message to see which restore step (chdir vs refreshSkillState vs git workspace) failed","As a last resort restart the coding-agent session to guarantee a consistent workspace state"],"exampleFix":"// before\nawait mode.changeDirectory(newCwd);\n// after\ntry {\n  await mode.changeDirectory(newCwd);\n} catch (e) {\n  if (String(e).includes(\"workspace may be inconsistent\")) {\n    await mode.changeDirectory(process.cwd()); // re-anchor to a known-good dir\n  }\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":"for (const dir of [newCwd, originalCwd]) {\n  await fs.access(dir, fs.constants.R_OK | fs.constants.X_OK); // both must be reachable\n}","typeGuard":null,"tryCatchPattern":"try {\n  await mode.changeDirectory(newCwd);\n} catch (err) {\n  if (String(err).includes(\"workspace may be inconsistent\")) {\n    // state untrusted: re-anchor or restart session\n    await mode.changeDirectory(process.cwd());\n  }\n  throw err;\n}","preventionTips":["Verify both the target and current directories are accessible before switching","Avoid switching to directories on network mounts that can drop mid-session","Capture the process cwd before switching so recovery is possible","On this error, restart the session rather than trusting workspace state"],"tags":["workspace","filesystem","state-inconsistency","directory-switch"],"backgroundTag":"workspace-restore-failed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}