grpc/grpc-java · error · IllegalArgumentException

Illegal log config pattern

Error message

Illegal log config pattern

What it means

When parsing the binlog options inside braces, FactoryImpl requires that a two-part (split by ';') option string start with 'h' for the header limit and 'm' for the message limit. Anything else, e.g. 'x:1;m:2' or reversed order 'm:1;h:2', throws IllegalArgumentException('Illegal log config pattern').

Solutions

  1. Order options as header first then message: '{h:<bytes>;m:<bytes>}'
  2. Use only 'h' and 'm' option prefixes, lowercase
  3. If only one limit is needed, drop the ';' and use a single 'h:...' or 'm:...' option

Example fix

// before
"*{m:100;h:2}"
// after
"*{h:2;m:100}"
Defensive patterns

Strategy: validation

Validate before calling

String opts = entry.substring(entry.indexOf('{') + 1, entry.length() - 1);
if (opts.contains(";")) {
  String[] p = opts.split(";", 2);
  if (!(p[0].startsWith("h") && p[1].startsWith("m"))) {
    throw new IllegalStateException("Options must be h then m: " + opts);
  }
}

Try / catch

try {
  BinlogHelper h = new BinlogHelper.FactoryImpl(sink, configStr);
} catch (IllegalArgumentException e) {
  // rewrite offending entry to {h:n;m:n} order
}

Prevention

When it happens

Trigger: A config entry whose option string contains ';' but whose parts do not start with 'h' and 'm' respectively, e.g. 'svc/Method{m:100;h:2}' or 'svc/Method{x;h:2}'.

Common situations: Writing options in the wrong order (m before h), using unknown option prefixes, or typos like 'H:' (uppercase).

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08). Data as JSON: /api/errors/6111f629f27e1397. Report an issue: GitHub.

Appendix: source

Thrown at services/src/main/java/io/grpc/protobuf/services/BinlogHelper.java:734

     *
     * <p>If the {@code logConfig} is null, the returned binlog will have a limit of
     * Integer.MAX_VALUE.
     */
    @VisibleForTesting
    @Nullable
    static BinlogHelper createBinaryLog(BinaryLogSink sink, @Nullable String logConfig) {
      if (logConfig == null) {
        return new BinlogHelper(
            new SinkWriterImpl(
                sink, TimeProvider.SYSTEM_TIME_PROVIDER, Integer.MAX_VALUE, Integer.MAX_VALUE));
      }
      try {
        final int maxHeaderBytes;
        final int maxMsgBytes;
        String[] parts = logConfig.split(";", 2);
        if (parts.length == 2) {
          if (!(parts[0].startsWith("h") && parts[1].startsWith("m"))) {
            throw new IllegalArgumentException("Illegal log config pattern");
          }
          maxHeaderBytes = optionalInt(parts[0].substring(1));
          maxMsgBytes = optionalInt(parts[1].substring(1));
        } else if (parts[0].startsWith("h")) {
          maxHeaderBytes = optionalInt(parts[0].substring(1));
          maxMsgBytes = 0;
        } else if (parts[0].startsWith("m")) {
          maxHeaderBytes = 0;
          maxMsgBytes = optionalInt(parts[0].substring(1));
        } else {
          throw new IllegalArgumentException("Illegal log config pattern");
        }
        return new BinlogHelper(
            new SinkWriterImpl(
                sink, TimeProvider.SYSTEM_TIME_PROVIDER, maxHeaderBytes, maxMsgBytes));
      } catch (NumberFormatException e) {
        throw new IllegalArgumentException("Illegal log config pattern");
      }

View on GitHub (pinned to 64daddc1f3)