bazelbuild/bazel · error · MissingFormatWidthException

incomplete format pattern ends with %: %s

Error message

incomplete format pattern ends with %: %s

What it means

Thrown by Starlark's printf-style %-formatting (Printer.formatString) when the pattern's last character is a lone '%'. A trailing % is treated as the start of a conversion but has no conversion character, so formatting aborts with MissingFormatWidthException carrying 'incomplete format pattern ends with %: <repr of pattern>'.

Source

Thrown at src/main/java/net/starlark/java/eval/Printer.java:400

    // whose constructor can take and display arbitrary error message, hence its use below.
    // TODO(adonovan): this suggests we're using the wrong exception. Throw IAE?

    int length = pattern.length();
    int argLength = arguments.size();
    int i = 0; // index of next character in pattern
    int a = 0; // index of next argument in arguments

    while (i < length) {
      int p = pattern.indexOf('%', i);
      if (p == -1) {
        printer.append(pattern, i, length);
        break;
      }
      if (p > i) {
        printer.append(pattern, i, p);
      }
      if (p == length - 1) {
        throw new MissingFormatWidthException(
            "incomplete format pattern ends with %: " + Starlark.repr(pattern, semantics));
      }
      char conv = pattern.charAt(p + 1);
      i = p + 2;

      // %%: literal %
      if (conv == '%') {
        printer.append('%');
        continue;
      }

      // get argument
      if (a >= argLength) {
        throw new MissingFormatWidthException(
            "not enough arguments for format pattern "
                + Starlark.repr(pattern, semantics)
                + ": "
                + Starlark.repr(Tuple.copyOf(arguments), semantics));

View on GitHub (pinned to e6e199d060)

Solutions

  1. Escape the literal percent: use %% wherever a literal % is wanted, including at the end.
  2. Prefer str.format-style or plain concatenation for text containing many literal percent signs.
  3. Lint format patterns for a trailing single % before use.

Example fix

# before
msg = "progress: %d%" % pct

# after
msg = "progress: %d%%" % pct
Defensive patterns

Strategy: validation

Validate before calling

def fmt(pattern):
    if pattern.endswith("%") and not pattern.endswith("%%"):
        fail("pattern ends with lone %: %r" % pattern)
    return pattern

Prevention

When it happens

Trigger: "100%" % (), "rate: %s%%" works but "rate: %s%" % (x,) fails; any pattern built by concatenation that leaves a single % at the end, e.g. "%s" + "%".

Common situations: Building human-readable messages with percentages ('completed 50%'); concatenating a variable suffix onto a format string; templates authored by non-Python users who don't know % must be doubled.

Related errors


AI-assisted analysis of bazelbuild/bazel@e6e199d060 (2026-08-14). Data as JSON: /api/errors/8286cf309863430f. Report an issue: GitHub.