upstash/context7 · error · Error

Unterminated TOML literal string in MCP args

Error message

Unterminated TOML literal string in MCP args

What it means

A single-quoted (literal) TOML string in the args array was opened but no closing single quote exists anywhere after it in the file.

Source

Thrown at packages/cli/src/setup/toml-editor.ts:74

    const width = escape === "u" ? 4 : 8;
    const hex = source.slice(index, index + width);
    if (!new RegExp(`^[0-9A-Fa-f]{${width}}$`).test(hex)) {
      throw new Error(`Invalid TOML Unicode escape \\${escape}${hex}`);
    }
    const codePoint = Number.parseInt(hex, 16);
    if (codePoint > 0x10ffff || (codePoint >= 0xd800 && codePoint <= 0xdfff)) {
      throw new Error(`Invalid TOML Unicode code point U+${hex}`);
    }
    value += String.fromCodePoint(codePoint);
    index += width;
  }
  throw new Error("Unterminated TOML basic string in MCP args");
}

function parseTomlLiteralString(source: string, start: number): TomlStringToken {
  const endQuote = source.indexOf("'", start + 1);
  if (endQuote === -1) throw new Error("Unterminated TOML literal string in MCP args");
  const value = source.slice(start + 1, endQuote);
  if (value.includes("\n") || value.includes("\r")) {
    throw new Error("Multiline strings are not supported in MCP args");
  }
  return { value, start, end: endQuote + 1 };
}

function parseTomlStringArray(
  source: string,
  start: number
): { tokens: TomlStringToken[]; end: number } {
  if (source[start] !== "[") throw new Error("Expected a TOML array for MCP args");

  const tokens: TomlStringToken[] = [];
  let index = start + 1;
  while (index < source.length) {
    index = skipTomlArrayTrivia(source, index);
    if (source[index] === "]") return { tokens, end: index + 1 };

View on GitHub (pinned to edc9eeb77b)

Solutions

  1. Add the closing single quote
  2. If the value contains an apostrophe, switch to a double-quoted basic string and escape as needed
  3. Check for smart quotes and replace with ASCII quotes

Example fix

// before
args = ['--greeting 'hello''
// after
args = ["--greeting 'hello'"]
Defensive patterns

Strategy: validation

Validate before calling

const idx = raw.indexOf("'");
// per line: literal strings must open and close on the same line
for (const line of raw.split('\n')) {
  if (((line.match(/'/g) ?? []).length) % 2 !== 0) throw new Error('Unterminated literal string');
}

Type guard

function literalStringClosed(line: string): boolean {
  return (line.match(/'/g) ?? []).length % 2 === 0;
}

Try / catch

catch (e) { if (/Unterminated TOML literal string/.test(e.message)) { /* close the string or switch to basic string */ } throw e; }

Prevention

When it happens

Trigger: args = ['--flag with no closing ', or the closing ' removed during editing; note literal strings cannot contain escapes so a stray ' inside the value ends the string early.

Common situations: Using a literal string for a value that itself contains an apostrophe (e.g. 'it's'); deleted closing quote; editor smart-quote substitution.

Related errors


AI-assisted analysis of upstash/context7@edc9eeb77b (2026-08-28). Data as JSON: /api/errors/2517f68d2028c59d. Report an issue: GitHub.