google-gemini/gemini-cli · error · Error

Invalid syntax${contextInfo}: Unclosed injection starting at

Error message

Invalid syntax${contextInfo}: Unclosed injection starting at index ${startIndex} ('${trigger}'). Ensure braces are balanced. Paths or commands with unbalanced braces are not supported directly.

What it means

Thrown by extractInjections() when a trigger sequence (e.g. '!{' for shell or '@{' for includes) is found but brace counting never returns to zero before the end of the string — i.e. the injection is unclosed. The parser does simple brace counting and has no escape mechanism, so unbalanced braces inside the content also trigger it.

Source

Thrown at packages/cli/src/services/prompt-processors/injectionParser.ts:82

          injections.push({
            content: injectionContent.trim(),
            startIndex,
            endIndex,
          });

          index = endIndex;
          foundEnd = true;
          break;
        }
      }
      currentIndex++;
    }

    // Check if the inner loop finished without finding the closing brace.
    if (!foundEnd) {
      const contextInfo = contextName ? ` in command '${contextName}'` : '';
      // Enforce strict parsing (Comment 1) and clarify limitations (Comment 2).
      throw new Error(
        `Invalid syntax${contextInfo}: Unclosed injection starting at index ${startIndex} ('${trigger}'). Ensure braces are balanced. Paths or commands with unbalanced braces are not supported directly.`,
      );
    }
  }

  return injections;
}

View on GitHub (pinned to 5024443c72)

Solutions

  1. Add the missing closing '}' so braces are balanced around the injection.
  2. If the command needs literal braces, wrap the whole command in balanced outer braces (e.g. '!{ sh -c "..." }') or avoid braces in the embedded command.
  3. Move brace-heavy logic into a script file invoked without inline braces.

Example fix

// before
Summarize !{awk '{print $1}' file.txt} output
// after
Summarize !{awk "{print \$1}" file.txt} output
// or simpler: avoid inline braces
Summarize !{./first-col.sh file.txt} output
Defensive patterns

Strategy: validation

Validate before calling

function injectionsAreClosed(prompt: string, trigger: string): boolean {
  let i = 0;
  while (i < prompt.length) {
    const start = prompt.indexOf(trigger, i);
    if (start === -1) break;
    let j = start + trigger.length, depth = 1;
    for (; j < prompt.length && depth > 0; j++) {
      if (prompt[j] === '{') depth++;
      else if (prompt[j] === '}') depth--;
    }
    if (depth !== 0) return false;
    i = j;
  }
  return true;
}
if (!injectionsAreClosed(prompt, '!{')) throw new Error('Unbalanced !{...} braces');

Type guard

function isBalancedInjection(prompt: string, trigger: string): boolean {
  return injectionsAreClosed(prompt, trigger);
}

Try / catch

try {
  extractInjections(prompt, '!{', cmdName);
} catch (e) {
  if (e instanceof Error && /Unclosed injection/.test(e.message)) {
    // fix the unbalanced braces, then retry
  }
  throw e;
}

Prevention

When it happens

Trigger: A prompt contains '!{echo hi' with no matching '}', or a command/path inside the braces itself contains an unmatched '{' or '}', so braceCount never reaches 0.

Common situations: Forgot the closing brace on a shell injection; used a command containing literal braces (awk, find -exec, JSON via echo); pasted a path with a stray brace.

Related errors


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