From 5c2752250745fb4c2a7a288dee8c04b8b02ecdb1 Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Tue, 9 Dec 2025 12:34:39 -0800 Subject: [PATCH] fix: prevent empty .vif files from ec.decode causing parse errors (#7686) * fix: prevent empty .vif files from ec.decode causing parse errors When ec.decode copies .vif files from EC shard nodes, if a source node doesn't have the .vif file, an empty .vif file was created on the target node. This caused volume.configure.replication to fail with 'proto: syntax error' when trying to parse the empty file. This fix: 1. In writeToFile: Remove empty files when no data was written (source file was not found) to avoid leaving corrupted empty files 2. In MaybeLoadVolumeInfo: Handle empty .vif files gracefully by treating them as non-existent, allowing the system to create a proper one Fixes #7666 * refactor: remove redundant dst.Close() and add error logging Address review feedback: - Remove redundant dst.Close() call since defer already handles it - Add error logging for os.Remove() failure --- weed/server/volume_grpc_copy.go | 9 +++++++++ weed/storage/volume_info/volume_info.go | 8 ++++++++ 2 files changed, 17 insertions(+) diff --git a/weed/server/volume_grpc_copy.go b/weed/server/volume_grpc_copy.go index 410c6b05d..2e20941ad 100644 --- a/weed/server/volume_grpc_copy.go +++ b/weed/server/volume_grpc_copy.go @@ -291,6 +291,15 @@ func writeToFile(client volume_server_pb.VolumeServer_CopyFileClient, fileName s } wt.MaybeSlowdown(int64(len(resp.FileContent))) } + // If no data was written (source file was not found), remove the empty file + // to avoid leaving corrupted empty files that cause parse errors later + if progressedBytes == 0 && !isAppend { + if removeErr := os.Remove(fileName); removeErr != nil { + glog.V(1).Infof("failed to remove empty file %s: %v", fileName, removeErr) + } else { + glog.V(1).Infof("removed empty file %s (source file not found)", fileName) + } + } return modifiedTsNs, nil } diff --git a/weed/storage/volume_info/volume_info.go b/weed/storage/volume_info/volume_info.go index 2ac4cc493..75cbc1472 100644 --- a/weed/storage/volume_info/volume_info.go +++ b/weed/storage/volume_info/volume_info.go @@ -42,6 +42,14 @@ func MaybeLoadVolumeInfo(fileName string) (volumeInfo *volume_server_pb.VolumeIn } + // Handle empty .vif files gracefully - treat as if file doesn't exist + // This can happen when ec.decode copies from a source that doesn't have a .vif file + if len(fileData) == 0 { + glog.Warningf("empty volume info file %s, treating as non-existent", fileName) + hasVolumeInfoFile = false + return + } + glog.V(1).Infof("maybeLoadVolumeInfo Unmarshal volume info %v", fileName) if err = jsonpb.Unmarshal(fileData, volumeInfo); err != nil { if oldVersionErr := tryOldVersionVolumeInfo(fileData, volumeInfo); oldVersionErr != nil {