{"record":{"id":"45298d5a3e0820fc","repo":"apache/pulsar","slug":"invalid-value-for-service-account-token-expiration","errorCode":null,"errorMessage":"Invalid value for SERVICE_ACCOUNT_TOKEN_EXPIRATION_SECONDS. Expected a long.","messagePattern":"Invalid value for SERVICE_ACCOUNT_TOKEN_EXPIRATION_SECONDS\\. Expected a long\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-functions/runtime/src/main/java/org/apache/pulsar/functions/auth/KubernetesServiceAccountTokenAuthProvider.java","lineNumber":97,"sourceCode":"                           java.util.function.Function<FunctionDetails, String> namespaceCustomizerFunc,\n                           Map<String, Object> config) {\n        setNamespaceProviderFunc(namespaceCustomizerFunc);\n        Object certSecretName = config.get(BROKER_CLIENT_TRUST_CERTS_SECRET_NAME);\n        if (certSecretName instanceof String) {\n            brokerTrustCertsSecretName = (String) certSecretName;\n        } else if (certSecretName != null) {\n            // Throw exception because user set this configuration, but it isn't valid.\n            throw new IllegalArgumentException(\"Invalid value for \" + BROKER_CLIENT_TRUST_CERTS_SECRET_NAME\n                    + \". Expected a string.\");\n        }\n        Object tokenExpirationSeconds = config.get(SERVICE_ACCOUNT_TOKEN_EXPIRATION_SECONDS);\n        if (tokenExpirationSeconds instanceof Long) {\n            serviceAccountTokenExpirationSeconds = (Long) tokenExpirationSeconds;\n        } else if (tokenExpirationSeconds instanceof String) {\n            try {\n                serviceAccountTokenExpirationSeconds = Long.parseLong((String) tokenExpirationSeconds);\n            } catch (NumberFormatException e) {\n                throw new IllegalArgumentException(\"Invalid value for \" + SERVICE_ACCOUNT_TOKEN_EXPIRATION_SECONDS\n                        + \". Expected a long.\");\n            }\n        } else if (tokenExpirationSeconds != null) {\n            // Throw exception because user set this configuration, but it isn't valid.\n            throw new IllegalArgumentException(\"Invalid value for \" + SERVICE_ACCOUNT_TOKEN_EXPIRATION_SECONDS\n                    + \". Expected a long.\");\n        }\n        Object tokenAudience = config.get(SERVICE_ACCOUNT_TOKEN_AUDIENCE);\n        if (tokenAudience instanceof String) {\n            serviceAccountTokenAudience = (String) tokenAudience;\n        } else if (tokenAudience != null) {\n            throw new IllegalArgumentException(\"Invalid value for \" + SERVICE_ACCOUNT_TOKEN_AUDIENCE\n                    + \". Expected a string.\");\n        }\n    }\n\n    @Override\n    public void configureAuthenticationConfig(AuthenticationConfig authConfig,","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/runtime/src/main/java/org/apache/pulsar/functions/auth/KubernetesServiceAccountTokenAuthProvider.java#L79-L115","documentation":"initialize() accepts SERVICE_ACCOUNT_TOKEN_EXPIRATION_SECONDS as a Long or a numeric String, but throws IllegalArgumentException when the String cannot be parsed by Long.parseLong. This fail-fast validation prevents silently running with an unset token expiration.","triggerScenarios":"SERVICE_ACCOUNT_TOKEN_EXPIRATION_SECONDS is provided as a String containing non-numeric text (e.g. \"1h\", \"7200s\", \"abc\") so Long.parseLong throws NumberFormatException and the error is rethrown.","commonSituations":"Users write durations with unit suffixes (\"30m\") or formatted numbers (\"7,200\") in YAML; config is read from an env var containing whitespace or a unit suffix.","solutions":["Change the value to a plain integer string (e.g. \"7200\") or an unquoted integer in the config.","If a duration suffix is needed, parse/convert it to seconds yourself before passing it into the auth config.","Trim whitespace and verify the value matches ^[0-9]+$ before calling initialize."],"exampleFix":"// before\nconfig.put(SERVICE_ACCOUNT_TOKEN_EXPIRATION_SECONDS, \"1h\");\n// after\nconfig.put(SERVICE_ACCOUNT_TOKEN_EXPIRATION_SECONDS, 3600L);","handlingStrategy":"validation","validationCode":"Object v = config.get(SERVICE_ACCOUNT_TOKEN_EXPIRATION_SECONDS);\nif (v instanceof String && !v.toString().trim().matches(\"^\\\\d+$\")) {\n    throw new IllegalArgumentException(\"SERVICE_ACCOUNT_TOKEN_EXPIRATION_SECONDS must be a plain integer (seconds), got: \" + v);\n}","typeGuard":"static boolean isValidExpiration(Object v) {\n    return v == null || v instanceof Long || (v instanceof String && ((String) v).trim().matches(\"^\\\\d+$\"));\n}","tryCatchPattern":"try {\n    provider.initialize(config);\n} catch (IllegalArgumentException e) {\n    log.error(\"Token expiration config invalid (use plain seconds, no unit suffix): {}\", e.getMessage());\n    throw e;\n}","preventionTips":["Express durations as plain integer seconds, never with 'h'/'m'/'s' suffixes","Trim and normalize strings from env vars before putting them in config","Prefer Long-typed values in programmatic config builders","Document the expected type next to the config key"],"tags":["kubernetes","functions-runtime","config-validation","number-format"],"backgroundTag":"invalid-number-format","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}