{"record":{"id":"a189f2f1f946082d","repo":"can1357/oh-my-pi","slug":"failed-to-persist-sourcename-session","errorCode":null,"errorMessage":"Failed to persist ${sourceName} session","messagePattern":"Failed to persist (.+?) session","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/modes/controllers/selector-controller.ts","lineNumber":1606,"sourceCode":"\t\t\tconst foreignByPath = new Map(foreignSessions.map(session => [session.path, session]));\n\t\t\tsessions = foreignSessions.map(foreignSessionInfoToSessionInfo);\n\t\t\tonSelectSession = async session => {\n\t\t\t\ttry {\n\t\t\t\t\tawait this.ctx.settings.flush();\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthis.ctx.showError(\n\t\t\t\t\t\t`Failed to save pending settings: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t\t);\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tconst foreignSession = foreignByPath.get(session.path);\n\t\t\t\tif (!foreignSession) throw new Error(`Selected ${sourceName} session is no longer available`);\n\t\t\t\tconst imported = await persistForeignSession(store, foreignSession, {\n\t\t\t\t\tfallbackCwd: this.ctx.sessionManager.getCwd(),\n\t\t\t\t\tsuppressBreadcrumb: true,\n\t\t\t\t});\n\t\t\t\tconst sessionFile = imported.getSessionFile();\n\t\t\t\tif (!sessionFile) throw new Error(`Failed to persist ${sourceName} session`);\n\t\t\t\tawait imported.close();\n\t\t\t\treturn await this.handleResumeSession(sessionFile, { settingsFlushed: true });\n\t\t\t};\n\t\t\tselectorOptions = {\n\t\t\t\ttitle: `Import ${sourceName} Session`,\n\t\t\t\tscopeLabel: false,\n\t\t\t\tshowCwd: true,\n\t\t\t};\n\t\t} else {\n\t\t\tconst [loadedSessions, pinnedIds] = await Promise.all([\n\t\t\t\tSessionManager.list(this.ctx.sessionManager.getCwd(), this.ctx.sessionManager.getSessionDir()),\n\t\t\t\tloadPinnedSessionIds(),\n\t\t\t]);\n\t\t\tsessions = loadedSessions;\n\t\t\tconst historyStorage = this.ctx.historyStorage;\n\t\t\tconst historyMatcher = historyStorage\n\t\t\t\t? (query: string) => historyStorage.matchingSessionIds(query)\n\t\t\t\t: undefined;","sourceCodeStart":1588,"sourceCodeEnd":1624,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/modes/controllers/selector-controller.ts#L1588-L1624","documentation":"SelectorController throws this when a foreign-source session (e.g. an imported/collab or external provider session) was selected and imported in memory, but persistForeignSession did not yield a session file on disk. The controller cannot resume a session without a backing file, so it aborts the import-and-resume flow. It signals an internal persistence failure, not a user-selection problem.","triggerScenarios":"Calling the selector's import flow (via handleSelect in SelectorController) when the imported session's getSessionFile() returns undefined — i.e. persistForeignSession completed but did not write/attach a session file path.","commonSituations":"Disk write failures or a session store misconfigured so the imported session has no file path; importing a foreign session whose serialization produced no file; running with a session manager pointed at an unwritable directory.","solutions":["Verify the session storage directory (sessionManager cwd / OMP data dir) is writable and has free space","Check persistForeignSession's store configuration — ensure a FileSessionStorage-backed store is used so a session file is created","Retry the import; if persistent, inspect logs for the underlying persistence error from persistForeignSession","Report the underlying persist failure — getSessionFile() being empty after a successful import is a bug in the import path"],"exampleFix":"// before\nconst imported = await persistForeignSession(store, foreignSession, { fallbackCwd });\nconst sessionFile = imported.getSessionFile();\n// after\nconst imported = await persistForeignSession(store, foreignSession, { fallbackCwd });\nconst sessionFile = imported.getSessionFile();\nif (!sessionFile) {\n  // ensure the store has a writable directory before persisting\n  await fs.mkdir(sessionDir, { recursive: true });\n  throw new Error(`Failed to persist ${sourceName} session`);\n}","handlingStrategy":"try-catch","validationCode":"const store = new FileSessionStorage({ dir: sessionDir });\nawait fs.access(sessionDir, fs.constants.W_OK); // storage dir must be writable","typeGuard":"function hasSessionFile(s: { getSessionFile(): string | undefined }): s is { getSessionFile(): string } {\n  return typeof s.getSessionFile() === \"string\" && s.getSessionFile().length > 0;\n}","tryCatchPattern":"try {\n  const session = await selector.importAndResume(foreignSession);\n} catch (err) {\n  if (err.message.startsWith(\"Failed to persist\")) {\n    ui.showError(\"Could not write the imported session to disk. Check disk space/permissions and retry.\");\n  } else throw err;\n}","preventionTips":["Ensure the session storage directory exists and is writable before importing","Monitor disk space where session files are written","Prefer FileSessionStorage-backed stores so imports always produce a file","Log persistForeignSession failures instead of swallowing them"],"tags":["session","persistence","import"],"backgroundTag":"session-persist-failed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}