apache/pulsar · warning · RestException
key '%s' doesn't exist.
Error message
key '%s' doesn't exist.
What it means
The state store returned no StateValue for the requested key, so the worker throws a 404 RestException "key '<key>' doesn't exist.". The function exists and the state store is reachable; only the key lookup came back empty.
Source
Thrown at pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/ComponentImpl.java:1276
log.error().attr("tenant", tenant).attr("namespace", namespace).attr("componentName", functionName)
.attr("key", key).exception(e).log("Invalid getFunctionState request @ / / / /");
throw new RestException(Status.BAD_REQUEST, e.getMessage());
}
FunctionMetaDataManager functionMetaDataManager = worker().getFunctionMetaDataManager();
if (!functionMetaDataManager.containsFunction(tenant, namespace, functionName)) {
log.warn().attr("tenant", tenant).attr("namespace", namespace).attr("componentName", functionName)
.log("getFunctionState 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);
StateValue value = store.getStateValue(key);
if (value == null) {
throw new RestException(Status.NOT_FOUND, "key '" + key + "' doesn't exist.");
}
byte[] data = value.getValue();
if (data == null) {
throw new RestException(Status.NOT_FOUND, "key '" + key + "' doesn't exist.");
}
ByteBuffer buf = ByteBuffer.wrap(data);
Long number = null;
if (buf.remaining() == Long.BYTES) {
number = buf.getLong();
}
if (Boolean.TRUE.equals(value.getIsNumber())) {
return new FunctionState(key, null, null, number, value.getVersion());
}
if (Utf8.isWellFormed(data)) {
return new FunctionState(key, new String(data, UTF_8), null, number, value.getVersion());View on GitHub (pinned to 820761864e)
Solutions
- Verify the exact key spelling/case used when the function stored the value.
- Confirm the function actually ran and put the key (check function logs / trigger it first).
- Query the correct tenant/namespace/function that owns the key.
- If data should exist, inspect the BookKeeper table service / state storage for the namespace to check for data loss.
Example fix
// before GET .../state/Counter -> key 'Counter' doesn't exist. // after (matching stored key) GET .../state/counter
Defensive patterns
Strategy: try-catch
Try / catch
try {
const state = await getState(tenant, ns, fn, key);
} catch (e) {
if (e.status === 404 && e.message.includes("doesn't exist")) {
// key absent: treat as default/zero or wait until the function writes it
return defaultValue;
}
throw e;
} Prevention
- Treat 'key doesn't exist' as a normal first-read condition (initialize defaults).
- Match key case exactly; state keys are case-sensitive.
- Ensure the function has actually run (e.g. trigger it) before reading its state.
When it happens
Trigger: GET .../functions/{tenant}/{namespace}/{functionName}/state/{key} where store.getStateValue(key) returns null — the key was never written, has expired/been deleted, or the query targets the wrong function's store.
Common situations: Reading a counter before the function ever incremented it; key-name case mismatch (state keys are case-sensitive); querying a different function instance's key; bookkeeper table-service data loss or store re-created.
Related errors
- '%s' is not found
- NamespaceIsolationPolicies for cluster ${cluster} does not e
- Cannot find NamespaceIsolationPolicy ${policyName} for clust
- Tenant not found
- Namespace does not exist
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/c2f59530a48bdb91.
Report an issue: GitHub.