{"record":{"id":"ccd84c9ff8edcbc6","repo":"jenkinsci/jenkins","slug":"null-value-not-allowed-as-an-environment-variable","errorCode":null,"errorMessage":"Null value not allowed as an environment variable: ${key}","messagePattern":"Null value not allowed as an environment variable: (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/hudson/EnvVars.java","lineNumber":379,"sourceCode":"    public static void resolve(Map<String, String> env) {\n        for (Map.Entry<String, String> entry : env.entrySet()) {\n            entry.setValue(Util.replaceMacro(entry.getValue(), env));\n        }\n    }\n\n    /**\n     * Convenience message\n     * @since 1.485\n     **/\n    public String get(String key, String defaultValue) {\n        String v = get(key);\n        if (v == null)    v = defaultValue;\n        return v;\n    }\n\n    @Override\n    public String put(String key, String value) {\n        if (value == null)    throw new IllegalArgumentException(\"Null value not allowed as an environment variable: \" + key);\n        return super.put(key, value);\n    }\n\n    /**\n     * Add a key/value but only if the value is not-null. Otherwise no-op.\n     * @since 1.556\n     */\n    public void putIfNotNull(String key, String value) {\n        if (value != null)\n            put(key, value);\n    }\n\n    /**\n     * Add entire map but filter null values out.\n     * @since 2.214\n     */\n    public void putAllNonNull(Map<String, String> map) {\n        map.forEach(this::putIfNotNull);","sourceCodeStart":361,"sourceCodeEnd":397,"githubUrl":"https://github.com/jenkinsci/jenkins/blob/2e228ff40b14dbc8b14ffbc6edf0e4383cf744fc/core/src/main/java/hudson/EnvVars.java#L361-L397","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Replace put with putIfNotNull when a null should be a no-op.","Use putAllNonNull when bulk-merging a map that may contain nulls.","Sanitize the source value: substitute an empty string or a default before put.","If using addLine, guard against empty values before calling put."],"exampleFix":"// before\nenvVars.put(\"PATH\", System.getenv(\"MISSING\")); // null -> throws\n// after\nenvVars.putIfNotNull(\"PATH\", System.getenv(\"MISSING\"));","handlingStrategy":"validation","validationCode":"if (value != null) {\n    envVars.put(key, value);\n} else {\n    // decide policy: skip, or put empty string\n}","typeGuard":"static boolean isSettableEnvValue(String v) { return v != null; }","tryCatchPattern":"try {\n    envVars.put(key, value);\n} catch (IllegalArgumentException e) {\n    // 'Null value not allowed' — fall back to a safe default or skip\n    envVars.putIfNotNull(key, value);\n}","preventionTips":["Prefer putIfNotNull / putAllNonNull when merging maps that may contain nulls.","Sanitize values from expand()/getenv() before put, since unresolved macros yield null.","Add a unit test asserting no null values reach EnvVars."],"tags":["env-vars","validation","null-safety"],"backgroundTag":null,"analyzedSha":"2e228ff40b14dbc8b14ffbc6edf0e4383cf744fc","analyzedAt":"2026-08-14T07:07:15.274Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}