google-gemini/gemini-cli · error · Error

Cannot write extension settings to ${envFilePath} because it

Error message

Cannot write extension settings to ${envFilePath} because it is a directory.

What it means

Thrown by the bulk write path (saveExtensionSettings / formatEnvContent caller) when the target env file path already exists and is a directory. The code stat()s envFilePath before fs.writeFile and refuses to overwrite a directory, because writing a file over a folder would either fail or corrupt the layout.

Source

Thrown at packages/cli/src/config/extensions/extensionSettings.ts:132

  const nonSensitiveSettings: Record<string, string> = {};
  for (const setting of settings) {
    const value = allSettings[setting.envVar];
    if (value === undefined || value === '') {
      continue;
    }
    if (setting.sensitive) {
      await keychain.setSecret(setting.envVar, value);
    } else {
      nonSensitiveSettings[setting.envVar] = value;
    }
  }

  const envContent = formatEnvContent(nonSensitiveSettings);

  if (fsSync.existsSync(envFilePath)) {
    const stat = fsSync.statSync(envFilePath);
    if (stat.isDirectory()) {
      throw new Error(
        `Cannot write extension settings to ${envFilePath} because it is a directory.`,
      );
    }
  }

  await fs.writeFile(envFilePath, envContent);
}

function formatEnvContent(settings: Record<string, string>): string {
  let envContent = '';
  for (const [key, value] of Object.entries(settings)) {
    if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(key)) {
      throw new Error(
        `Invalid environment variable name: "${key}". Must contain only alphanumeric characters and underscores.`,
      );
    }
    if (value.includes('\n') || value.includes('\r')) {
      throw new Error(

View on GitHub (pinned to 5024443c72)

Solutions

  1. Inspect envFilePath and remove or rename the directory blocking the write.
  2. Change the storage location so the settings file does not collide with an existing directory.
  3. Add a pre-write stat check in the caller and surface a clearer prompt before this throw.

Example fix

// before
await fs.writeFile(envFilePath, envContent);  // throws if envFilePath is a dir
// after
if (fsSync.existsSync(envFilePath) && fsSync.statSync(envFilePath).isDirectory()) {
  throw new Error(`Refusing to overwrite directory at ${envFilePath}; remove it first.`);
}
await fs.writeFile(envFilePath, envContent);
Defensive patterns

Strategy: validation

Validate before calling

import fsSync from 'node:fs';
function ensureWritableFile(envFilePath: string) {
  if (fsSync.existsSync(envFilePath) && fsSync.statSync(envFilePath).isDirectory()) {
    throw new Error(`${envFilePath} is a directory, not a writable file`);
  }
}

Try / catch

try { await saveExtensionSettings(...); } catch (e) { if (String(e).includes('because it is a directory')) { /* prompt user to remove dir */ } throw e; }

Prevention

When it happens

Trigger: A directory named EXTENSION_SETTINGS_FILENAME (e.g. .env) already exists at the location returned by getEnvFilePath (workspace dir or ExtensionStorage env file path). Reached when writing all non-sensitive extension settings at once.

Common situations: A user or script manually created a folder named like the env settings file; a previous tooling bug created a directory where a file was expected; a symlink loop resolves to a directory.

Related errors


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