jenkinsci/jenkins · error · IllegalArgumentException

Null value not allowed as an environment variable: ${key}

Error message

Null value not allowed as an environment variable: ${key}

What it means

EnvVars overrides Map.put to reject null values with IllegalArgumentException because environment variables cannot represent null. This enforces a hard invariant at the boundary rather than letting a null silently propagate into process spawning or serialization. Use putIfNotNull or putAllNonNull when null is a legitimate 'absent' signal.

Source

Thrown at core/src/main/java/hudson/EnvVars.java:379

    public static void resolve(Map<String, String> env) {
        for (Map.Entry<String, String> entry : env.entrySet()) {
            entry.setValue(Util.replaceMacro(entry.getValue(), env));
        }
    }

    /**
     * Convenience message
     * @since 1.485
     **/
    public String get(String key, String defaultValue) {
        String v = get(key);
        if (v == null)    v = defaultValue;
        return v;
    }

    @Override
    public String put(String key, String value) {
        if (value == null)    throw new IllegalArgumentException("Null value not allowed as an environment variable: " + key);
        return super.put(key, value);
    }

    /**
     * Add a key/value but only if the value is not-null. Otherwise no-op.
     * @since 1.556
     */
    public void putIfNotNull(String key, String value) {
        if (value != null)
            put(key, value);
    }

    /**
     * Add entire map but filter null values out.
     * @since 2.214
     */
    public void putAllNonNull(Map<String, String> map) {
        map.forEach(this::putIfNotNull);

View on GitHub (pinned to 2e228ff40b)

Solutions

  1. Replace put with putIfNotNull when a null should be a no-op.
  2. Use putAllNonNull when bulk-merging a map that may contain nulls.
  3. Sanitize the source value: substitute an empty string or a default before put.
  4. If using addLine, guard against empty values before calling put.

Example fix

// before
envVars.put("PATH", System.getenv("MISSING")); // null -> throws
// after
envVars.putIfNotNull("PATH", System.getenv("MISSING"));
Defensive patterns

Strategy: validation

Validate before calling

if (value != null) {
    envVars.put(key, value);
} else {
    // decide policy: skip, or put empty string
}

Type guard

static boolean isSettableEnvValue(String v) { return v != null; }

Try / catch

try {
    envVars.put(key, value);
} catch (IllegalArgumentException e) {
    // 'Null value not allowed' — fall back to a safe default or skip
    envVars.putIfNotNull(key, value);
}

Prevention

When it happens

Trigger: Calling envVars.put("KEY", null); passing a map value that resolved to null (e.g., via expand/replaceMacro that left a variable unresolved); merging an external map that contains null values; addLine on a malformed 'KEY=' line.

Common situations: Reading env from a map that may hold nulls; expanding ${VAR} where VAR is unset returns null; config-provided environment block with an empty value; JDK code path calling putAll with a map containing nulls.

Related errors


AI-assisted analysis of jenkinsci/jenkins@2e228ff40b (2026-08-14). Data as JSON: /api/errors/ccd84c9ff8edcbc6. Report an issue: GitHub.