{"record":{"id":"ced475e2c3a40d13","repo":"apache/seatunnel","slug":"post-sync-backup-failed-backup-target-path-is-emp","errorCode":null,"errorMessage":"Post-sync backup failed: backup target path is empty, splitId={}, source={}","messagePattern":"Post-sync backup failed: backup target path is empty, splitId=(.+?), source=(.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"seatunnel-connectors-v2/connector-file/connector-file-base/src/main/java/org/apache/seatunnel/connectors/seatunnel/file/source/split/ContinuousMultipleTableFileSourceSplitEnumerator.java","lineNumber":823,"sourceCode":"        }\n    }\n\n    private static String sha256Hex(byte[] bytes) {\n        char[] digits = \"0123456789abcdef\".toCharArray();\n        char[] encoded = new char[bytes.length * 2];\n        for (int i = 0; i < bytes.length; i++) {\n            int current = bytes[i] & 0xff;\n            encoded[i * 2] = digits[current >>> 4];\n            encoded[i * 2 + 1] = digits[current & 0x0f];\n        }\n        return new String(encoded);\n    }\n\n    private OpCommitResult commitBackupOperation(\n            TableScanContext ctx, FileSourceOperationState op, long checkpointId)\n            throws IOException {\n        if (StringUtils.isBlank(op.getBackupTargetPath())) {\n            log.warn(\n                    \"Post-sync backup failed: backup target path is empty, splitId={}, source={}\",\n                    op.getSplitId(),\n                    maskUriUserInfo(op.getSourcePath()));\n            return OpCommitResult.FAILED_RETRYABLE;\n        }\n\n        String stagingPath = buildBackupStagingPath(op);\n        FileStatus sourceStatus = getFileStatusIfPresent(ctx.sourceFs, op.getSourcePath());\n        FileStatus targetStatus = getFileStatusIfPresent(ctx.sourceFs, op.getBackupTargetPath());\n        FileStatus stagingStatus = getFileStatusIfPresent(ctx.sourceFs, stagingPath);\n\n        if (sourceStatus == null) {\n            if (targetStatus != null) {\n                if (isOperationContentMatched(ctx, op, op.getBackupTargetPath(), targetStatus)) {\n                    log.info(\n                            \"Post-sync backup completed during a previous attempt: source={}, target={}, \"\n                                    + \"checkpointId={}, capturedLen={}, capturedMtime={}\",\n                            maskUriUserInfo(op.getSourcePath()),","sourceCodeStart":805,"sourceCodeEnd":841,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-connectors-v2/connector-file/connector-file-base/src/main/java/org/apache/seatunnel/connectors/seatunnel/file/source/split/ContinuousMultipleTableFileSourceSplitEnumerator.java#L805-L841","documentation":"This WARN is emitted by the file source split enumerator when a post-sync backup operation reaches checkpoint commit but the operation state carries a blank backupTargetPath. Without a destination the backup rename cannot proceed, so the enumerator returns FAILED_RETRYABLE and the operation is retried at the next checkpoint. It indicates the operation was registered without a backup path being resolved.","triggerScenarios":"A FileSourceOperationState for action=backup was created with an unset/blank backup target path (e.g. backup configuration missing or path resolution failed upstream) and commitBackupOperation() runs during checkpoint commit.","commonSituations":"Misconfigured backup/backup-path option so the target is never populated; an operator state written by an older connector version that predates the backup-target field being restored into a newer job; a bug in path resolution returning empty string.","solutions":["Set the backup target path option correctly in the file source config so every backup operation gets a non-blank destination","Check how FileSourceOperationState was serialized/restored from checkpoint/operator state; ensure the backupTargetPath field is populated on restore","Inspect upstream code that builds the backup target path (path resolution/templating) for empty-string results","Verify the connector version matches between checkpoint savepoint and the running job"],"exampleFix":"// before\nbackup-path = \n// after\nbackup-path = hdfs:///warehouse/backup/${table}","handlingStrategy":"validation","validationCode":"// Before registering/committing a backup operation, assert the target path is set\nif (op.getBackupTargetPath() == null || op.getBackupTargetPath().isBlank()) {\n    throw new IllegalArgumentException(\n        \"backupTargetPath must be resolved before committing backup op \" + op.getSplitId());\n}","typeGuard":"boolean hasBackupTarget(FileSourceOperationState op) {\n    return op != null && op.getBackupTargetPath() != null && !op.getBackupTargetPath().isBlank();\n}","tryCatchPattern":null,"preventionTips":["Always configure the backup target path option; validate non-empty at job-configuration parse time","Unit-test the code path that builds FileSourceOperationState to assert backupTargetPath is populated","When upgrading connector versions, validate restored operator state for new required fields"],"tags":["hadoop","file-source","backup","retryable"],"backgroundTag":"missing-required-config-field","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}