google-gemini/gemini-cli · error
EINVAL
EINVAL
Error message
Failed to resolve plan path: ${err instanceof Error ? err.message : String(err)} What it means
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.
Source
Thrown at packages/core/src/tools/write-file.ts:141
if (config.isPlanMode()) {
try {
const cleanFilePath = filePath.replace(/\0/g, '');
const planPath = resolveAndValidatePlanPath(
cleanFilePath,
config.storage.getPlansDir(),
config.getProjectRoot(),
);
resolvedPath = resolveToRealPath(planPath);
} catch (err) {
return {
originalContent: '',
correctedContent: proposedContent,
fileExists: false,
error: {
message:
'Failed to resolve plan path: ' +
(err instanceof Error ? err.message : String(err)),
code: 'EINVAL',
},
};
}
} else {
const sanitizedPath = resolveDefensiveToolPath(
filePath,
config.getTargetDir(),
);
try {
resolvedPath = resolveToRealPath(
path.resolve(config.getTargetDir(), sanitizedPath),
);
} catch (err) {
return {
originalContent: '',
correctedContent: proposedContent,
fileExists: false,
error: {View on GitHub (pinned to 5024443c72)
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.
Example fix
// before await getCorrectedFileContent(config, '../../../etc/foo', content, signal); // after await getCorrectedFileContent(config, 'foo.md', content, signal);
Defensive patterns
Strategy: validation
Validate before calling
// reject bad plan paths before calling getCorrectedFileContent
const clean = filePath.replace(/\0/g, '');
if (path.isAbsolute(clean) || clean.includes('..')) throw new Error('plan path must be relative and inside plans dir'); Type guard
function isPlanPathError(res: unknown): boolean {
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');
} Try / catch
const res = await getCorrectedFileContent(config, filePath, content, signal);
if (res.error?.code === 'EINVAL') { return toolResultError(res.error.message); } Prevention
- Keep plan paths relative and under getPlansDir().
- Switch out of plan mode for writes that target the real workspace.
When it happens
Trigger: 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' } }.
Common situations: 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.
Related errors
- EACCES
- Path validation failed: ${pathError}
- Workspace path ${resolvedPath} is outside the allowed root d
- User requested to change authentication method
- User cancelled account validation
AI-assisted analysis of google-gemini/gemini-cli@5024443c72 (2026-08-12).
Data as JSON: /api/errors/769a0aab348fef8c.
Report an issue: GitHub.