{"record":{"id":"8d2406731882eb81","repo":"apache/pulsar","slug":"timeout-during-delete-operation","errorCode":null,"errorMessage":"Timeout during delete operation","messagePattern":"Timeout during delete operation","errorType":"exception","errorClass":"ManagedLedgerException","httpStatus":null,"severity":"error","filePath":"managed-ledger/src/main/java/org/apache/bookkeeper/mledger/impl/ManagedCursorImpl.java","lineNumber":2566,"sourceCode":"            public void deleteFailed(ManagedLedgerException exception, Object ctx) {\n                result.exception = exception;\n\n                if (timeout.get()) {\n                    log.warn()\n                            .attr(\"positions\", positions)\n                            .log(\"Delete operation timeout, callback deleteFailed\");\n                }\n\n                counter.countDown();\n            }\n        }, null);\n\n        if (!counter.await(ManagedLedgerImpl.AsyncOperationTimeoutSeconds, TimeUnit.SECONDS)) {\n            timeout.set(true);\n            log.warn()\n                    .attr(\"positions\", positions)\n                    .log(\"Delete operation timeout, no callback triggered\");\n            throw new ManagedLedgerException(\"Timeout during delete operation\");\n        }\n\n        if (result.exception != null) {\n            throw result.exception;\n        }\n    }\n\n\n    @Override\n    public void asyncDelete(Iterable<Position> positions, AsyncCallbacks.DeleteCallback callback, Object ctx) {\n        if (isClosed()) {\n            callback.deleteFailed(new ManagedLedgerException\n                    .CursorAlreadyClosedException(\"Cursor was already closed\"), ctx);\n            return;\n        }\n\n        Position newMarkDeletePosition = null;\n","sourceCodeStart":2548,"sourceCodeEnd":2584,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/managed-ledger/src/main/java/org/apache/bookkeeper/mledger/impl/ManagedCursorImpl.java#L2548-L2584","documentation":"The TRANSIENT (local filesystem) jcloud provider's validate() checks that a bucket is configured and throws IllegalArgumentException when config.getBucket() is null or empty. For the 'transient' (Local) offload driver the bucket maps to the local directory used to store offloaded data, so it is mandatory.","triggerScenarios":"Running offload with driver configured to the transient/local provider while managedLedgerOffloadBucket (TieredStorageConfiguration.getBucket()) is not set in broker.conf or the offload request properties.","commonSituations":"Testing local offload without setting managedLedgerOffloadBucket, copying config from a cloud provider example that omits the bucket, or bucket set under the wrong namespace/property name so the offloader sees empty.","solutions":["Set managedLedgerOffloadBucket=<local-directory-name> in broker.conf (or the topic-level offload properties).","Confirm the driver you intend is actually selected — if you meant cloud offload, set managedLedgerOffloadDriver correctly (e.g. s3) and supply its config.","Ensure the property is in the right config file that the broker/offloader loads and was not overridden by an empty value in a higher-priority source."],"exampleFix":"// before: broker.conf\nmanagedLedgerOffloadDriver=transient\n# no bucket configured\n\n// after:\nmanagedLedgerOffloadDriver=transient\nmanagedLedgerOffloadBucket=pulsar-offload-local","handlingStrategy":"validation","validationCode":"// before enabling transient offload, check the effective config\nif (config.getBucket() == null || config.getBucket().isEmpty()) {\n    throw new IllegalStateException(\"managedLedgerOffloadBucket must be set for transient/local offload\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    provider.validate(tieringConfig);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"Bucket cannot be empty\")) {\n        log.error(\"Add managedLedgerOffloadBucket to broker.conf for the configured driver\");\n    }\n    throw e;\n}","preventionTips":["Add managedLedgerOffloadBucket whenever you set a managedLedgerOffloadDriver.","Smoke-test offload configuration with a test topic after broker config changes.","Grep your broker.conf for empty managedLedgerOffload* overrides.","Document required per-driver properties in your deployment templates."],"tags":["configuration","validation","offload","bucket"],"backgroundTag":"missing-config-property","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"}