{"record":{"id":"f985288440ee5e91","repo":"apache/beam","slug":"rcsp-subsequent-run-that-doesn-t-hold-the-lock-this-is-not","errorCode":null,"errorMessage":"RCSP  {} : Subsequent run that doesn't hold the lock {}. This is not unexpected and should probably be reviewed.","messagePattern":"RCSP  (.+?) : Subsequent run that doesn't hold the lock (.+?)\\. This is not unexpected and should probably be reviewed\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigtable/changestreams/action/ReadChangeStreamPartitionAction.java","lineNumber":172,"sourceCode":"            \"RCSP  {} : Could not acquire lock with uid: {}, because this is a \"\n                + \"duplicate and another worker is working  on this partition already.\",\n            formatByteStringRange(partitionRecord.getPartition()),\n            partitionRecord.getUuid());\n        StreamProgress streamProgress = new StreamProgress();\n        streamProgress.setFailToLock(true);\n        metrics.decPartitionStreamCount();\n        tracker.tryClaim(streamProgress);\n        return ProcessContinuation.stop();\n      }\n    } else if (tracker.currentRestriction().getCloseStream() == null\n        && !metadataTableDao.doHoldLock(\n            partitionRecord.getPartition(), partitionRecord.getUuid())) {\n      // We only verify the lock if we are not holding CloseStream because if this is a retry of\n      // CloseStream we might have already cleaned up the lock in a previous attempt.\n      // Failed correctness check on this worker holds the lock on this partition. This shouldn't\n      // fail because there's a restriction tracker which means this worker has already acquired the\n      // lock and once it has acquired the lock it shouldn't fail the lock check.\n      LOG.warn(\n          \"RCSP  {} : Subsequent run that doesn't hold the lock {}. This is not unexpected and \"\n              + \"should probably be reviewed.\",\n          formatByteStringRange(partitionRecord.getPartition()),\n          partitionRecord.getUuid());\n      StreamProgress streamProgress = new StreamProgress();\n      streamProgress.setFailToLock(true);\n      metrics.decPartitionStreamCount();\n      tracker.tryClaim(streamProgress);\n      return ProcessContinuation.stop();\n    }\n\n    // Process CloseStream if it exists\n    CloseStream closeStream = tracker.currentRestriction().getCloseStream();\n    if (closeStream != null) {\n      LOG.debug(\"RCSP: Processing CloseStream\");\n      metrics.decPartitionStreamCount();\n      if (closeStream.getStatus().getCode() == Status.Code.OK) {\n        // We need to update watermark here. We're terminating this stream because we have reached","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigtable/changestreams/action/ReadChangeStreamPartitionAction.java#L154-L190","documentation":"ReadChangeStreamPartitionAction.run logs 'RCSP <partition>: Subsequent run that doesn't hold the lock <uuid>' when a retried attempt of the same partition/uuid does not pass the lock verification, meaning this worker is processing a partition whose lock it does not (or no longer) hold. The connector marks streamProgress.setFailToLock(true) so the partition is re-assigned.","triggerScenarios":"A bundle retry of ReadChangeStreamPartitionAction for the same PartitionRecord uuid after the lock was released/cleaned up (e.g. a retry of CloseStream), or the restriction tracker/lock state changed between attempts.","commonSituations":"Runner-level bundle retries after transient failures; work stealing/reassignment where another worker already processed the partition; race during CloseStream cleanup.","solutions":["Usually safe to ignore: the connector fails the lock and the partition will be retried/assigned correctly.","If it repeats persistently, check for multiple pipeline instances streaming the same change stream concurrently.","Verify the app profile allows multi-row transactions and that the metadata table is healthy.","Report/upgrade if the lock check consistently fails despite a single runner (known review-needed warning per the message)."],"exampleFix":"// before\n// two streaming jobs reading the same change stream -> lock contention\n// after\n// stop the duplicate job; keep exactly one ReadChangeStream pipeline per stream","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { partitionAction.run(record, receiver); } catch (RuntimeException e) { /* runner retries; connector sets failToLock and reassigns the partition */ }","preventionTips":["Ensure only one job consumes each change stream.","Use an app profile that allows safe retries (single-row transactions).","Investigate persistent occurrences — they indicate duplicated consumers or lock-state bugs."],"tags":["java","apache-beam","bigtable","change-stream","locking"],"backgroundTag":"invalid-state-transition","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}