apache/pulsar · error · IllegalArgumentException
Invalid state value
Error message
Invalid state value
What it means
putFunctionState accepts exactly one of byteValue, stringValue, or numberValue in the FunctionState body. When byteValue is null/empty and neither stringValue nor numberValue is set, the worker throws IllegalArgumentException("Invalid state value"), which the surrounding catch converts to a 500 RestException. The request carried no usable value payload.
Source
Thrown at pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/ComponentImpl.java:1362
FunctionMetaDataManager functionMetaDataManager = worker().getFunctionMetaDataManager();
if (!functionMetaDataManager.containsFunction(tenant, namespace, functionName)) {
log.warn().attr("tenant", tenant).attr("namespace", namespace).attr("componentName", functionName)
.log("putFunctionState does not exist @ / / /");
throw new RestException(Status.NOT_FOUND, String.format("'%s' is not found", functionName));
}
try {
DefaultStateStore store = worker().getStateStoreProvider().getStateStore(tenant, namespace, functionName);
ByteBuffer data;
if (state.getByteValue() == null || state.getByteValue().length == 0) {
if (state.getStringValue() != null) {
data = ByteBuffer.wrap(state.getStringValue().getBytes(UTF_8));
} else if (state.getNumberValue() != null) {
data = ByteBuffer.allocate(Long.BYTES);
data.putLong(state.getNumberValue());
} else {
throw new IllegalArgumentException("Invalid state value");
}
} else {
data = ByteBuffer.wrap(state.getByteValue());
}
store.put(key, data);
} catch (Throwable e) {
log.error().attr("tenant", tenant).attr("namespace", namespace).attr("componentName", functionName)
.attr("key", key).exception(e).log("Error while putFunctionState request @ / / / /");
throw new RestException(Status.INTERNAL_SERVER_ERROR, e.getMessage());
}
}
@Override
public void uploadFunction(final InputStream uploadedInputStream, final String path,
AuthenticationParameters authParams) {
if (!isWorkerServiceAvailable()) {View on GitHub (pinned to 820761864e)
Solutions
- Include exactly one value field in the body: stringValue (string), numberValue (long), or byteValue (base64 bytes).
- Check field names — the server expects stringValue/numberValue/byteValue, not generic "value".
- Ensure byteValue base64 decodes to a non-empty byte array if you intend a byte write.
- Expect a 500 here despite it being a client payload problem; fix the payload rather than retrying.
Example fix
// before: no value in body -> 500 'Invalid state value'
curl -X PUT .../state/counter -d '{"key":"counter"}'
// after
curl -X PUT .../state/counter -d '{"key":"counter","stringValue":"42"}' Defensive patterns
Strategy: validation
Validate before calling
// Exactly one value variant must be set
function validStateBody(state) {
const set = [!!state.stringValue, state.numberValue != null,
Array.isArray(state.byteValue) && state.byteValue.length > 0].filter(Boolean).length;
return set === 1 && typeof state.key === 'string' && state.key.length > 0;
} Type guard
function hasValue(state) {
return state != null && (
(typeof state.stringValue === 'string') ||
(typeof state.numberValue === 'number') ||
(Array.isArray(state.byteValue) && state.byteValue.length > 0));
} Try / catch
try {
await putState(tenant, ns, fn, key, body);
} catch (e) {
if (e.status === 500 && e.message.includes("Invalid state value")) {
// payload problem despite 500: add stringValue/numberValue/byteValue and retry
} else throw e;
} Prevention
- Always set exactly one of stringValue, numberValue, or byteValue in the FunctionState body.
- Use the exact field names stringValue/numberValue/byteValue in JSON.
- Never send an empty byteValue array with no alternative value set.
- Remember this condition surfaces as HTTP 500, not 400 — treat matching 500s as payload bugs.
When it happens
Trigger: PUT .../functions/{tenant}/{namespace}/{functionName}/state/{key} with a body like {"key":"k"} — byteValue null/empty, stringValue null, numberValue null. Note the 500 status (not 400) because the IllegalArgumentException is caught by the generic Throwable handler.
Common situations: Clients serializing FunctionState objects with all value fields unset; JSON field name mismatches (e.g. sending "value" instead of "stringValue"); base64 byteValue decoded to an empty array on the server; omitting the value when only intending to update a key.
Related errors
- '%s' is not found
- Path key doesn't match key in json
- cluster data is required
- Peer cluster ${peerCluster} does not exist
- Cluster ${cluster} does not exist.
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/d101a6db2b71920e.
Report an issue: GitHub.