{"record":{"id":"378cd9b78fba63bd","repo":"google-gemini/gemini-cli","slug":"invalid-environment-variable-value-for-key-v","errorCode":null,"errorMessage":"Invalid environment variable value for \"${key}\". Values cannot contain newlines.","messagePattern":"Invalid environment variable value for \"(.+?)\"\\. Values cannot contain newlines\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/config/extensions/extensionSettings.ts","lineNumber":150,"sourceCode":"      throw new Error(\n        `Cannot write extension settings to ${envFilePath} because it is a directory.`,\n      );\n    }\n  }\n\n  await fs.writeFile(envFilePath, envContent);\n}\n\nfunction formatEnvContent(settings: Record<string, string>): string {\n  let envContent = '';\n  for (const [key, value] of Object.entries(settings)) {\n    if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(key)) {\n      throw new Error(\n        `Invalid environment variable name: \"${key}\". Must contain only alphanumeric characters and underscores.`,\n      );\n    }\n    if (value.includes('\\n') || value.includes('\\r')) {\n      throw new Error(\n        `Invalid environment variable value for \"${key}\". Values cannot contain newlines.`,\n      );\n    }\n    const formattedValue = value.includes(' ')\n      ? `\"${value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')}\"`\n      : value;\n    envContent += `${key}=${formattedValue}\\n`;\n  }\n  return envContent;\n}\n\nexport async function promptForSetting(\n  setting: ExtensionSetting,\n): Promise<string | undefined> {\n  const response = await prompts({\n    type: setting.sensitive ? 'password' : 'text',\n    name: 'value',\n    message: `${setting.name}\\n${setting.description}`,","sourceCodeStart":132,"sourceCodeEnd":168,"githubUrl":"https://github.com/google-gemini/gemini-cli/blob/5024443c7217464a66e98f80d73172a26440bd8f/packages/cli/src/config/extensions/extensionSettings.ts#L132-L168","documentation":"Thrown by formatEnvContent() when a setting value contains a newline (\\n or \\r). .env files are line-oriented, so an embedded newline would silently inject a second assignment and corrupt or exfiltrate configuration; the library rejects it rather than attempting escaping.","triggerScenarios":"A user enters a multi-line value in a prompt, or a value is pasted from a file that includes a trailing CR/CRLF; the value is forwarded unchanged into nonSensitiveSettings and reaches formatEnvContent.","commonSituations":"Pasting private keys or certificates that contain newlines into a single-line prompt; Windows line endings (\\r\\n) in pasted text; JSON/multi-line tokens stored as a single setting.","solutions":["Strip newlines from the value before storing it, or encode it (e.g., base64) if line breaks are meaningful.","Mark the setting as sensitive so it is stored in the keychain (sensitive settings bypass formatEnvContent).","Split the multi-line value into multiple settings."],"exampleFix":"// before\nnonSensitiveSettings[envVar] = rawUserInput;  // rawUserInput has a trailing \\n\n// after\nnonSensitiveSettings[envVar] = rawUserInput.replace(/[\\r\\n]+/g, '').trim();","handlingStrategy":"validation","validationCode":"function assertSingleLine(key: string, value: string) {\n  if (/\\r|\\n/.test(value)) throw new Error(`Value for ${key} contains newlines`);\n}","typeGuard":"function isSingleLine(value: string): boolean { return !/[\\r\\n]/.test(value); }","tryCatchPattern":null,"preventionTips":["Trim and reject multiline input at the prompt layer.","For values that legitimately span lines (keys/certs), mark the setting sensitive so it goes to the keychain."],"tags":["extensions","settings","validation","env","config"],"backgroundTag":null,"analyzedSha":"5024443c7217464a66e98f80d73172a26440bd8f","analyzedAt":"2026-08-12T06:01:53.711Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}