{"record":{"id":"850eee208856d8c8","repo":"apache/flink","slug":"unable-to-create-recoverable-outputstream-as-lengt","errorCode":null,"errorMessage":"Unable to create recoverable outputstream as length of file {} is less than recoverable offset {}","messagePattern":"Unable to create recoverable outputstream as length of file (.+?) is less than recoverable offset (.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"critical","filePath":"flink-filesystems/flink-azure-fs-hadoop/src/main/java/org/apache/flink/fs/azurefs/AzureBlobFsRecoverableDataOutputStream.java","lineNumber":121,"sourceCode":"                                + tempFile\n                                + \" file is not found\");\n            }\n        } else {\n            long len = fs.getFileStatus(tempFile).getLen();\n            LOG.info(\n                    \"The recoverable offset is {} and the file len is {}\",\n                    recoverable.offset(),\n                    len);\n            // Happens when we recover from a previously committed offset. Otherwise this is not\n            // really needed\n            if (len > recoverable.offset()) {\n                truncate(fs, recoverable);\n            } else if (len < recoverable.offset()) {\n                LOG.error(\n                        \"Temp file length {} is less than the expected recoverable offset {}\",\n                        len,\n                        recoverable.offset());\n                throw new IOException(\n                        \"Unable to create recoverable outputstream as length of file \"\n                                + len\n                                + \" is less than \"\n                                + \"recoverable offset \"\n                                + recoverable.offset());\n            }\n        }\n        out = fs.append(tempFile);\n        if (out.getPos() == 0) {\n            // In ABFS when we try to append we don't account for the initial file size like we do\n            // in DFS.\n            // So we explicitly store this and when we do a persist call we make use of it.\n            // This we have raised a bug in ABFS hadoop driver side. Once fixed this will not be\n            // needed. So it should be ok to put this in side the 'if' check.\n            initialFileSize = fs.getFileStatus(tempFile).getLen();\n        }\n        LOG.debug(\"Created a new OS for appending {}\", tempFile);\n    }","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/apache/flink/blob/2f3c205e9266cb30240eb7f4fdab15cad629a70f/flink-filesystems/flink-azure-fs-hadoop/src/main/java/org/apache/flink/fs/azurefs/AzureBlobFsRecoverableDataOutputStream.java#L103-L139","documentation":"Thrown by AzureBlobFsRecoverableDataOutputStream during recovery when the temp file exists but its length is LESS than the recoverable offset from the last persist(). That means part of the acknowledged data never made it to storage (truncated/uncommitted blocks), so appending from the offset would produce a corrupt file; the writer refuses to continue.","triggerScenarios":"Recovery where Azure Blob did not retain all uncommitted appended data: append-block timeouts, server-side truncation, or a mismatch between the offset recorded at persist() and what ABFS actually committed.","commonSituations":"ABFS append operations that failed silently before persist; recovering across a storage outage; Hadoop ABFS client version differences in flush/append semantics.","solutions":["Fall back to the last completed checkpoint and let the sink rewrite the file part","Upgrade flink-azure-fs-hadoop and the Hadoop ABFS client to a version with stable append/flush semantics","Report with the two numbers from the log line ('Temp file length {} is less than the expected recoverable offset {}') — it indicates data actually lost between persist and recovery","Reduce the sink in-progress state age (more frequent checkpoints) so less data is at risk"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    writer.recover(recoverable);\n} catch (java.io.IOException e) {\n    // offset > stored length means data loss: do not append; re-emit from checkpoint\n    handleUnrecoverableInProgressState(e);\n}","preventionTips":["Checkpoint often to bound the amount of in-flight uncommitted data","Keep flink-azure-fs-hadoop and Hadoop ABFS client versions aligned and current","Avoid killing TaskManagers with SIGKILL during heavy append phases when possible"],"tags":["azure","abfs","recovery","truncation","file-sink"],"backgroundTag":null,"analyzedSha":"2f3c205e9266cb30240eb7f4fdab15cad629a70f","analyzedAt":"2026-08-14T08:48:24.518Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}