quarkusio/quarkus · error · IllegalArgumentException

The level of the root logger cannot be set to null

Error message

The level of the root logger cannot be set to null

What it means

LogStreamJsonRPCService.updateLogLevel() sets a java.util.logging level for a named logger. If levelValue is null/blank, it inherits the parent logger's level; but when the target logger has no parent (i.e. it is the root logger), there is nothing to inherit, so it throws IllegalArgumentException that the root logger level cannot be set to null.

Source

Thrown at extensions/devui/runtime/src/main/java/io/quarkus/devui/runtime/logstream/LogStreamJsonRPCService.java:98

                    "effectiveLevel", getEffectiveLogLevel(logger),
                    "configuredLevel", getConfiguredLogLevel(logger));
        }
        return null;
    }

    @NonBlocking
    @JsonRpcDescription("Update a specific logger's log level in this Quarkus application")
    @DevMCPEnableByDefault
    public JsonObject updateLogLevel(@JsonRpcDescription("The name of the logger") String loggerName,
            @JsonRpcDescription("The new level of the logger") String levelValue) {
        LogContext logContext = LogContext.getLogContext();
        Logger logger = logContext.getLogger(loggerName);
        java.util.logging.Level level;
        if (levelValue == null || levelValue.isBlank()) {
            if (logger.getParent() != null) {
                level = logger.getParent().getLevel();
            } else {
                throw new IllegalArgumentException("The level of the root logger cannot be set to null");
            }
        } else {
            level = Level.parse(levelValue);
        }
        logger.setLevel(level);
        LOG.info("Log level updated [" + loggerName + "] changed to [" + levelValue + "]");

        return getLogger(loggerName);
    }

    private static String toLogLine(JsonObject json) {
        return String.format(
                "%s %s [%s] (%s) %s",
                json.getString("timestamp"),
                json.getString("level"),
                json.getString("loggerName"),
                json.getString("threadName"),
                json.getString("formattedMessage"));

View on GitHub (pinned to e1c734241f)

Solutions

  1. Send a valid level name (SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST, ALL, OFF)
  2. Only send null/blank level for non-root loggers to mean 'inherit parent'
  3. Guard in the Dev UI form to require a level when the target is the root logger

Example fix

// before
updateLogLevel("", ""); // root logger, blank level
// after
updateLogLevel("", "INFO"); // or pick a non-root logger for inheritance
Defensive patterns

Strategy: validation

Validate before calling

const LEVELS = ['SEVERE','WARNING','INFO','CONFIG','FINE','FINER','FINEST','ALL','OFF'];
if ((levelValue == null || levelValue === '') && isRootLogger(loggerName)) levelValue = 'INFO';

Type guard

const isKnownLevel = v => typeof v === 'string' && LEVELS.includes(v.toUpperCase());

Try / catch

try { rpc.call('logstream/updateLogLevel', { loggerName, levelValue }); }
catch (e) { if (String(e.message).includes('root logger')) { /* send an explicit level instead */ } else { throw e; } }

Prevention

When it happens

Trigger: Invoking the Dev UI log-stream JSON-RPC updateLogLevel with an empty or null level for the root logger (loggerName empty or "" resolving to a parentless logger).

Common situations: Front-end sending an empty level string when the user clears the level input for the ROOT logger; also triggered by Level.parse failing separately for garbage values.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/910c8182d251caa4. Report an issue: GitHub.