{"record":{"id":"8d27a7538fb46333","repo":"vercel/ai","slug":"cline-private-session-directory-json-stringify-p","errorCode":null,"errorMessage":"Cline private session directory ${JSON.stringify(privateSessionDir)} must be outside sessionWorkDir ${JSON.stringify(input.sessionWorkDir)}.","messagePattern":"Cline private session directory (.+?) must be outside sessionWorkDir (.+?)\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/harness-cline/src/cline-resume-state.ts","lineNumber":61,"sourceCode":"  readonly sessionWorkDir: string;\n  readonly sessionId: string;\n}): string {\n  const sessionKey = createHash('sha256').update(input.sessionId).digest('hex');\n  const privateSessionDir = path.posix.join(\n    input.sandboxHomeDir,\n    '.ai-sdk',\n    'harness-cline',\n    sessionKey,\n  );\n  const relativePath = path.posix.relative(\n    input.sessionWorkDir,\n    privateSessionDir,\n  );\n  if (\n    relativePath === '' ||\n    (!relativePath.startsWith('../') && !path.posix.isAbsolute(relativePath))\n  ) {\n    throw new Error(\n      `Cline private session directory ${JSON.stringify(privateSessionDir)} must be outside sessionWorkDir ${JSON.stringify(input.sessionWorkDir)}.`,\n    );\n  }\n  return privateSessionDir;\n}\n\nfunction resolveContainedSandboxPath(input: {\n  readonly privateSessionDir: string;\n  readonly historyFileName: string;\n}): string {\n  const historyDir = path.posix.resolve(input.privateSessionDir);\n  const filePath = path.posix.resolve(\n    historyDir,\n    safeClineHistoryFileName(input.historyFileName),\n  );\n  const relativePath = path.posix.relative(historyDir, filePath);\n  if (\n    relativePath === '' ||","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/vercel/ai/blob/69428b1f8b037e4d118fb4853428d5c4e620493c/packages/harness-cline/src/cline-resume-state.ts#L43-L79","documentation":"When resolving a Cline private session directory, the harness verifies the resolved directory lies strictly outside the session working directory using path.posix.relative. If the resulting relative path is empty (same directory) or does not escape via '../' and is not absolute, the configuration is considered unsafe and this error is thrown. The harness requires private session state to be isolated from the shared session work directory.","triggerScenarios":"Calling createClineSession (via resolveClinePrivateSessionDirectory) with privateSessionDir set equal to sessionWorkDir, or set to a relative path that resolves to a subdirectory inside sessionWorkDir (e.g. './private' inside the work dir), so path.posix.relative returns '' or a non-'../' path.","commonSituations":"Configuring privateSessionDir as a subfolder of the session work directory for convenience; passing the same base path to both options; copy-pasting config where sessionWorkDir was changed to a broader parent directory that now contains the private dir; using a relative path whose resolution lands inside the work dir.","solutions":["Set privateSessionDir to a directory on a different branch of the filesystem than sessionWorkDir (e.g. a sibling directory or a path under a dedicated state root).","Verify with path.posix.relative(sessionWorkDir, privateSessionDir) that the result starts with '../' or is absolute before calling the API.","If you intended the private dir to be a subfolder, instead create a sibling folder outside sessionWorkDir and point privateSessionDir at it."],"exampleFix":"// before\ncreateClineSession({ sessionWorkDir: '/work/session-1', privateSessionDir: '/work/session-1/private' });\n// after\ncreateClineSession({ sessionWorkDir: '/work/session-1', privateSessionDir: '/work/.cline-private/session-1' });","handlingStrategy":"validation","validationCode":"import path from 'node:path';\nfunction isPrivateDirOutsideWorkDir(sessionWorkDir: string, privateSessionDir: string): boolean {\n  const rel = path.posix.relative(path.posix.resolve(sessionWorkDir), path.posix.resolve(privateSessionDir));\n  return rel !== '' && (rel.startsWith('../') || path.posix.isAbsolute(rel));\n}\nif (!isPrivateDirOutsideWorkDir(input.sessionWorkDir, input.privateSessionDir)) {\n  throw new Error('privateSessionDir must be outside sessionWorkDir');\n}","typeGuard":null,"tryCatchPattern":"try {\n  const session = await createClineSession(input);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('must be outside sessionWorkDir')) {\n    // fix config: choose a sibling/external directory\n  } else throw e;\n}","preventionTips":["Keep private Cline state under a dedicated root (e.g. ~/.cline-private or a sibling of the work dir), never inside it.","Add a unit test asserting path.posix.relative(workDir, privateDir).startsWith('../') for your default config.","If sessionWorkDir is dynamic, compute privateSessionDir from a fixed root, not from the work dir."],"tags":["configuration","path-validation","cline"],"backgroundTag":"path-outside-allowed-directory","analyzedSha":"69428b1f8b037e4d118fb4853428d5c4e620493c","analyzedAt":"2026-08-30T12:32:21.016Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}