{"record":{"id":"769a0aab348fef8c","repo":"google-gemini/gemini-cli","slug":"einval","errorCode":"EINVAL","errorMessage":"Failed to resolve plan path: ${err instanceof Error ? err.message : String(err)}","messagePattern":"Failed to resolve plan path: (.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/core/src/tools/write-file.ts","lineNumber":141,"sourceCode":"  if (config.isPlanMode()) {\n    try {\n      const cleanFilePath = filePath.replace(/\\0/g, '');\n      const planPath = resolveAndValidatePlanPath(\n        cleanFilePath,\n        config.storage.getPlansDir(),\n        config.getProjectRoot(),\n      );\n      resolvedPath = resolveToRealPath(planPath);\n    } catch (err) {\n      return {\n        originalContent: '',\n        correctedContent: proposedContent,\n        fileExists: false,\n        error: {\n          message:\n            'Failed to resolve plan path: ' +\n            (err instanceof Error ? err.message : String(err)),\n          code: 'EINVAL',\n        },\n      };\n    }\n  } else {\n    const sanitizedPath = resolveDefensiveToolPath(\n      filePath,\n      config.getTargetDir(),\n    );\n    try {\n      resolvedPath = resolveToRealPath(\n        path.resolve(config.getTargetDir(), sanitizedPath),\n      );\n    } catch (err) {\n      return {\n        originalContent: '',\n        correctedContent: proposedContent,\n        fileExists: false,\n        error: {","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/google-gemini/gemini-cli/blob/5024443c7217464a66e98f80d73172a26440bd8f/packages/core/src/tools/write-file.ts#L123-L159","documentation":"EINVAL 'Failed to resolve plan path' is returned (not thrown) by getCorrectedFileContent when, in plan mode, resolveAndValidatePlanPath or resolveToRealPath throws. The result object carries code:'EINVAL' so the write-file tool can report the bad path without crashing.","triggerScenarios":"config.isPlanMode() is true -> cleanFilePath = filePath.replace(/\\0/g,'') -> resolveAndValidatePlanPath(...) or resolveToRealPath(planPath) throws -> catch returns { error:{ message:'Failed to resolve plan path: '+err.message, code:'EINVAL' } }.","commonSituations":"Model emits a file_path that escapes the plans dir (../), points to a symlink that leaves the workspace, contains characters the path validator rejects, or references an unreadable path while in plan mode.","solutions":["Ensure the path is relative and stays inside config.storage.getPlansDir().","Reject/null out '\\0' and any symlink that resolves outside the workspace before calling.","Switch out of plan mode if the write legitimately targets a non-plan path."],"exampleFix":"// before\nawait getCorrectedFileContent(config, '../../../etc/foo', content, signal);\n// after\nawait getCorrectedFileContent(config, 'foo.md', content, signal);","handlingStrategy":"validation","validationCode":"// reject bad plan paths before calling getCorrectedFileContent\nconst clean = filePath.replace(/\\0/g, '');\nif (path.isAbsolute(clean) || clean.includes('..')) throw new Error('plan path must be relative and inside plans dir');","typeGuard":"function isPlanPathError(res: unknown): boolean {\n  return typeof res === 'object' && res !== null && (res as any).error?.code === 'EINVAL' && typeof (res as any).error?.message === 'string' && (res as any).error.message.startsWith('Failed to resolve plan path');\n}","tryCatchPattern":"const res = await getCorrectedFileContent(config, filePath, content, signal);\nif (res.error?.code === 'EINVAL') { return toolResultError(res.error.message); }","preventionTips":["Keep plan paths relative and under getPlansDir().","Switch out of plan mode for writes that target the real workspace."],"tags":["plan-mode","path-validation","einval","typescript"],"backgroundTag":null,"analyzedSha":"5024443c7217464a66e98f80d73172a26440bd8f","analyzedAt":"2026-08-12T06:01:53.711Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}