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

  1. Ensure the path is relative and stays inside config.storage.getPlansDir().
  2. Reject/null out '\0' and any symlink that resolves outside the workspace before calling.
  3. 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

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


AI-assisted analysis of google-gemini/gemini-cli@5024443c72 (2026-08-12). Data as JSON: /api/errors/769a0aab348fef8c. Report an issue: GitHub.