{"record":{"id":"c7cd3862d82e33f2","repo":"apache/pulsar","slug":"failed-to-retrieve-counter-from-key-s","errorCode":null,"errorMessage":"Failed to retrieve counter from key '%s'","messagePattern":"Failed to retrieve counter from key '(.+?)'","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"pulsar-functions/instance/src/main/java/org/apache/pulsar/functions/instance/state/BKStateStoreImpl.java","lineNumber":112,"sourceCode":"    public void incrCounter(String key, long amount) {\n        try {\n            result(incrCounterAsync(key, amount));\n        } catch (Exception e) {\n            throw new RuntimeException(\"Failed to increment key '\" + key + \"' by amount '\" + amount + \"'\", e);\n        }\n    }\n\n    @Override\n    public CompletableFuture<Long> getCounterAsync(String key) {\n        return table.getNumber(Unpooled.wrappedBuffer(key.getBytes(UTF_8)));\n    }\n\n    @Override\n    public long getCounter(String key) {\n        try {\n            return result(getCounterAsync(key));\n        } catch (Exception e) {\n            throw new RuntimeException(\"Failed to retrieve counter from key '\" + key + \"'\");\n        }\n    }\n\n    @Override\n    public CompletableFuture<Void> putAsync(String key, ByteBuffer value) {\n        if (value != null) {\n            // Set position to off the buffer to the beginning.\n            // If a user used an operation like ByteBuffer.allocate(4).putInt(count)\n            // to create a ByteBuffer to store to the state store\n            // the position of the buffer will be at the end and nothing will be written to table service\n            value.position(0);\n            return table.put(\n                    Unpooled.wrappedBuffer(key.getBytes(UTF_8)),\n                    Unpooled.wrappedBuffer(value));\n        } else {\n            return table.put(\n                    Unpooled.wrappedBuffer(key.getBytes(UTF_8)),\n                    null);","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/instance/src/main/java/org/apache/pulsar/functions/instance/state/BKStateStoreImpl.java#L94-L130","documentation":"BKStateStoreImpl.getCounter blocks on getCounterAsync and rethrows any failure as a RuntimeException with this message. Note the cause is intentionally dropped here (no `e` passed), so only the message is available in logs. It means reading the counter value for the key from the BookKeeper-backed state table failed.","triggerScenarios":"Calling getCounter(key) when the async table getNumber fails — storage service error, timeout, connection failure, or the table containing the key is unavailable. Also thrown if result() unwraps a failed future of any kind.","commonSituations":"State table not initialized; BookKeeper/table-proxy outage; deserialization/number-format issues on the stored value; first read of a never-incremented key in a failing cluster.","solutions":["Since the cause is swallowed, check instance logs for the async failure logged at the table layer.","Verify the state table exists and the storage cluster is reachable.","Call getCounterAsync instead to get the real completion exception from the future.","Initialize the counter with incrCounter(key, 0) before reading if your workflow requires it to exist."],"exampleFix":"// before\nlong c = store.getCounter(\"hits\"); // message loses cause\n// after\nlong c = store.getCounterAsync(\"hits\").exceptionally(ex -> {\n    log.error(\"getCounter failed\", ex);\n    return 0L;\n}).join();","handlingStrategy":"fallback","validationCode":"// initialize the counter before reading if it may not exist\nstore.incrCounter(\"hits\", 0); // no-op if the table supports it, ensures key path works","typeGuard":null,"tryCatchPattern":"long hits;\ntry {\n    hits = store.getCounter(\"hits\");\n} catch (RuntimeException e) {\n    // cause is swallowed; log and fall back to async to capture it\n    hits = store.getCounterAsync(\"hits\").handle((v, ex) -> {\n        if (ex != null) { log.error(\"counter read failed\", ex); return 0L; }\n        return v;\n    }).join();\n}","preventionTips":["Prefer the Async variants when you need the underlying exception — the sync wrapper drops the cause.","Initialize counters before first read.","Alert on storage-cluster health instead of per-call exceptions."],"tags":["state","bookkeeper","counter","blocking-call"],"backgroundTag":"state-store-operation-failed","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}