{"record":{"id":"2999be4c7266dee4","repo":"apache/flink","slug":"interrupted-while-acquiring-lock-2999be","errorCode":null,"errorMessage":"interrupted while acquiring lock","messagePattern":"interrupted while acquiring lock","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"warning","filePath":"flink-filesystems/flink-s3-fs-native/src/main/java/org/apache/flink/fs/s3native/writer/NativeS3RecoverableFsDataOutputStream.java","lineNumber":315,"sourceCode":"                            key,\n                            uploadId,\n                            e);\n                }\n                if (cleanupException != null) {\n                    throw cleanupException;\n                }\n            }\n        } finally {\n            unlock();\n        }\n    }\n\n    private void lock() throws IOException {\n        try {\n            lock.lockInterruptibly();\n        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n            throw new IOException(\"interrupted while acquiring lock\", e);\n        }\n    }\n\n    private void unlock() {\n        lock.unlock();\n    }\n}\n","sourceCodeStart":297,"sourceCodeEnd":323,"githubUrl":"https://github.com/apache/flink/blob/2f3c205e9266cb30240eb7f4fdab15cad629a70f/flink-filesystems/flink-s3-fs-native/src/main/java/org/apache/flink/fs/s3native/writer/NativeS3RecoverableFsDataOutputStream.java#L297-L323","documentation":"lock() uses lockInterruptibly(); if the thread is interrupted while waiting for the stream's reentrant lock, it re-asserts the interrupt flag and wraps the failure in IOException(\"interrupted while acquiring lock\"). This makes interruption visible to Flink's I/O error handling instead of being swallowed inside a lock acquisition.","triggerScenarios":"Two threads use the stream (one holds the lock in write/flush/commit), and the waiting thread is interrupted — job cancellation is the canonical case: Flink interrupts task threads on cancel while another thread holds the stream lock.","commonSituations":"Job cancellation during heavy S3 upload activity; failover racing a concurrent flush; user code sharing one recoverable stream across a timer thread and the mailbox thread.","solutions":["Treat this as expected during cancellation: catch IOException in shutdown paths, check Thread.currentThread().isInterrupted(), and exit cleanly.","Avoid sharing the stream across threads — confine it to one thread/actor to remove lock contention entirely.","Ensure any code that catches this exception does not mask the interrupt flag (the stream already re-set it; propagate or honor it).","If seen outside cancellation, look for long lock holders (slow uploads inside write) and shorten critical sections."],"exampleFix":"// before\ncatch (IOException e) { log.error(\"write failed\", e); }\n\n// after\ncatch (IOException e) {\n    if (Thread.currentThread().isInterrupted()) {\n        // job is being cancelled — release resources quietly\n        return;\n    }\n    throw e;\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    stream.write(...);\n} catch (IOException e) {\n    if (Thread.currentThread().isInterrupted()) {\n        // cancellation in progress — unwind quietly\n        return;\n    }\n    throw e;\n}","preventionTips":["Confine each stream to one thread.","Expect interruption during job cancellation; handle it in shutdown paths.","Never clear the interrupt flag when catching this error."],"tags":["s3","concurrency","interruption","cancellation","io"],"backgroundTag":null,"analyzedSha":"2f3c205e9266cb30240eb7f4fdab15cad629a70f","analyzedAt":"2026-08-14T08:48:24.518Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}