{"record":{"id":"8cf0e850346d2f6d","repo":"can1357/oh-my-pi","slug":"acp-cwd-must-be-absolute-cwd","errorCode":null,"errorMessage":"ACP cwd must be absolute: ${cwd}","messagePattern":"ACP cwd must be absolute: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/modes/acp/acp-agent.ts","lineNumber":1681,"sourceCode":"\t}\n\n\tasync #emitCommandOutput(record: ManagedSessionRecord, text: string): Promise<void> {\n\t\tif (!text) {\n\t\t\treturn;\n\t\t}\n\t\tawait this.#connection.sessionUpdate({\n\t\t\tsessionId: record.session.sessionId,\n\t\t\tupdate: {\n\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\tcontent: { type: \"text\", text },\n\t\t\t\tmessageId: crypto.randomUUID(),\n\t\t\t},\n\t\t});\n\t}\n\n\t#assertAbsoluteCwd(cwd: string): void {\n\t\tif (!path.isAbsolute(cwd)) {\n\t\t\tthrow new Error(`ACP cwd must be absolute: ${cwd}`);\n\t\t}\n\t}\n\n\t#convertPromptBlocks(blocks: PromptRequest[\"prompt\"]): { text: string; images: AgentImageContent[] } {\n\t\tconst textParts: string[] = [];\n\t\tconst images: AgentImageContent[] = [];\n\t\tfor (const block of blocks) {\n\t\t\tswitch (block.type) {\n\t\t\t\tcase \"text\":\n\t\t\t\t\ttextParts.push(block.text);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"image\":\n\t\t\t\t\timages.push({ type: \"image\", data: block.data, mimeType: block.mimeType });\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"resource\":\n\t\t\t\t\tif (\"text\" in block.resource) {\n\t\t\t\t\t\ttextParts.push(block.resource.text);\n\t\t\t\t\t} else if (typeof block.resource.mimeType === \"string\" && block.resource.mimeType.startsWith(\"image/\")) {","sourceCodeStart":1663,"sourceCodeEnd":1699,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/modes/acp/acp-agent.ts#L1663-L1699","documentation":"Thrown by #assertAbsoluteCwd when a session creation/load request supplies a relative cwd. The ACP contract requires absolute working directories so the agent resolves tool calls and file paths unambiguously; relative paths would depend on the agent process's own cwd.","triggerScenarios":"session/new, session/load, session/resume, or fork requests where params.cwd is relative (e.g. \"src\", \"./\", \"~/proj\" without expansion).","commonSituations":"Clients that pass the project-relative directory instead of an absolute path; unexpanded `~` home shorthand; scripts that forget path.resolve().","solutions":["Resolve the cwd to an absolute path with path.resolve() before sending the request.","Expand `~` (os.homedir()) before sending.","If only a relative path is available, resolve it against a known base directory on the client side."],"exampleFix":"// before\nawait agent.newSession({ cwd: \"packages/app\" });\n// after\nimport * as path from \"node:path\";\nawait agent.newSession({ cwd: path.resolve(\"packages/app\") });","handlingStrategy":"validation","validationCode":"import * as path from \"node:path\";\nconst absCwd = path.resolve(cwd.replace(/^~(?=\\/|$)/, process.env.HOME ?? \"\"));\nif (!path.isAbsolute(absCwd)) throw new Error(`cwd must be absolute: ${cwd}`);\nawait agent.newSession({ cwd: absCwd });","typeGuard":null,"tryCatchPattern":"try {\n  await agent.newSession({ cwd });\n} catch (err) {\n  if (err.message.startsWith(\"ACP cwd must be absolute:\")) {\n    return agent.newSession({ cwd: path.resolve(cwd) });\n  }\n  throw err;\n}","preventionTips":["Always path.resolve() cwd before sending ACP requests.","Expand `~` and environment variables into absolute paths client-side.","Make ACP client wrappers normalize cwd once, at the API boundary."],"tags":["acp","validation","path"],"backgroundTag":"relative-path-not-allowed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}