JetBrains/intellij-community · error · FormatDecode.IllegalFormatException

duplicate flag '' '' in

Error message

duplicate flag ''{0}'' in ''{1}''

What it means

IllegalFormatException from FormatDecode when the same flag appears twice in one specifier — detected by (flagBits | bit) == flagBits, i.e. the bit was already set. java.util.Formatter likewise rejects duplicate flags ('Duplicate format flag %s in format string'). The inspection reports it statically at the flagged specifier.

Solutions

  1. Deduplicate flags in the specifier (keep one occurrence)
  2. If building format strings dynamically, track applied flags in a Set before appending

Example fix

// before
String.format("%--5s", "x")
// after
String.format("%-5s", "x")
Defensive patterns

Strategy: validation

Validate before calling

static boolean noDuplicateFlags(String flags) {
  return flags.chars().distinct().count() == flags.length();
}

Try / catch

try { FormatDecode.decode(fmt, argc); } catch (IllegalFormatException e) { /* report duplicated flag character */ }

Prevention

When it happens

Trigger: Specifiers like '%--5s', '%00d', '%,,f'; decode() iterates the flag characters and re-setting an already-set bit throws.

Common situations: Concatenating flag strings programmatically so a flag is appended twice; copy-paste edits duplicating a character; regex-built formats in logging wrappers.

Related errors


AI-assisted analysis of JetBrains/intellij-community@be881553f2 (2026-08-14). Data as JSON: /api/errors/df47fc8ff2e767f1. Report an issue: GitHub.

Appendix: source

Thrown at java/java-analysis-impl/src/com/siyeh/ig/format/FormatDecode.java:256

        isAllVerifier = true;
      }
      final String specifier = matcher.group();
      final String posSpec = matcher.group("posSpec");
      final String flags = matcher.group("flags");
      final String width = matcher.group("width");
      final String precision = matcher.group("precision");
      final String dateSpec = matcher.group("dateSpec");
      final @NonNls String conversion = matcher.group("conversion");

      int flagBits = 0;
      for (int j = 0; j < flags.length(); j++) {
        final char flag = flags.charAt(j);
        final int bit = flag(flag);
        if (bit == -1) {
          throw new IllegalFormatException(InspectionGadgetsBundle.message("format.string.error.unexpected.flag", flag, specifier));
        }
        if ((flagBits | bit) == flagBits) {
          throw new IllegalFormatException(InspectionGadgetsBundle.message("format.string.error.duplicate.flag", flag, specifier));
        }
        flagBits |= bit;
      }

      // check this first because it should not affect "implicit"
      if ("n".equals(conversion)) {
        // no flags allowed
        checkFlags(flagBits, 0, specifier);
        if (!StringUtil.isEmpty(width)) {
          throw new IllegalFormatException(InspectionGadgetsBundle.message("format.string.error.width.not.allowed", width, specifier));
        }
        checkNoPrecision(precision, specifier);
        continue;
      }
      else if ("%".equals(conversion)) { // literal '%'
        checkFlags(flagBits, LEFT_JUSTIFY, specifier);
        checkNoPrecision(precision, specifier);
        continue;

View on GitHub (pinned to be881553f2)