google-gemini/gemini-cli · error · Error

Missing required variable: ${key}

Error message

Missing required variable: ${key}

What it means

Thrown by validateVariables when a key in the VariableSchema is marked required: true but the VariableContext has no value (undefined/empty) for that key. hydrateString calls validateVariables first, so any required template variable that is unset aborts hydration.

Source

Thrown at packages/cli/src/config/extensions/variables.ts:47

  | string
  | number
  | boolean
  | null
  | JsonObject
  | JsonArray;

export type VariableContext = {
  [key: string]: string | undefined;
};

export function validateVariables(
  variables: VariableContext,
  schema: VariableSchema,
) {
  for (const key in schema) {
    const definition = schema[key];
    if (definition.required && !variables[key]) {
      throw new Error(`Missing required variable: ${key}`);
    }
  }
}

export function hydrateString(str: string, context: VariableContext): string {
  validateVariables(context, VARIABLE_SCHEMA);
  const regex = /\${(.*?)}/g;
  return str.replace(regex, (match, key) => {
    const val = context[key];
    return val == null ? match : String(val);
  });
}

export function recursivelyHydrateStrings<T>(
  obj: T,
  values: VariableContext,
): T {
  if (typeof obj === 'string') {

View on GitHub (pinned to 5024443c72)

Solutions

  1. Supply the missing variable in the VariableContext passed to hydrateString.
  2. If the variable is genuinely optional, mark it required:false in the schema.
  3. Resolve values (workspace dir, extension path) before hydration and pass them explicitly.

Example fix

// before
hydrateString('${extensionPath}/bin/run', { });
// after
hydrateString('${extensionPath}/bin/run', { extensionPath: resolvedExtDir });
Defensive patterns

Strategy: validation

Validate before calling

function hasAllRequired(context: VariableContext, schema: VariableSchema): boolean {
  return Object.entries(schema).every(([k, d]) => !d.required || (context[k] != null && context[k] !== ''));
}

Type guard

function hasRequiredVars(context: VariableContext, schema: VariableSchema): boolean { for (const k in schema) { if (schema[k].required && !context[k]) return false; } return true; }

Prevention

When it happens

Trigger: Calling hydrateString on a template that references ${extensionPath} (or another required variable) without supplying that variable in the context; the built-in VARIABLE_SCHEMA marks certain keys required.

Common situations: Extension invoked outside a workspace so extensionPath is undefined; a custom schema marks a variable required but the caller forgets to populate it; env var removed between runs.

Related errors


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