{"record":{"id":"19795a90f6c7b4e9","repo":"CoplayDev/unity-mcp","slug":"file-hash-mismatch-remoteentry-key-shorthash","errorCode":null,"errorMessage":"File hash mismatch: {remoteEntry.Key} ({ShortHash(localBlobSha)} != {ShortHash(remoteEntry.Value)})","messagePattern":"File hash mismatch: (.+?) \\((.+?) != (.+?)\\)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"MCPForUnity/Editor/Setup/SkillSyncService.cs","lineNumber":481,"sourceCode":"\n            RemoveEmptyDirectories(targetRoot);\n        }\n\n        private static void ValidateFileHashes(string installRoot, Dictionary<string, string> remoteFiles, StringComparison pathComparison, Action<string> log)\n        {\n            var checkedCount = 0;\n            foreach (var remoteEntry in remoteFiles)\n            {\n                var localPath = ResolvePathUnderRoot(installRoot, remoteEntry.Key, pathComparison);\n                if (!File.Exists(localPath))\n                {\n                    throw new InvalidOperationException($\"Missing synced file: {remoteEntry.Key}\");\n                }\n\n                var localBlobSha = ComputeGitBlobSha1(localPath);\n                if (!string.Equals(localBlobSha, remoteEntry.Value, StringComparison.Ordinal))\n                {\n                    throw new InvalidOperationException($\"File hash mismatch: {remoteEntry.Key} ({ShortHash(localBlobSha)} != {ShortHash(remoteEntry.Value)})\");\n                }\n\n                checkedCount++;\n            }\n\n            log?.Invoke($\"Hash checks passed ({checkedCount}/{remoteFiles.Count}).\");\n        }\n\n        internal static string ComputeGitBlobSha1(string filePath)\n        {\n            var bytes = File.ReadAllBytes(filePath);\n            return ComputeGitBlobSha1(bytes);\n        }\n\n        internal static string ComputeGitBlobSha1(byte[] bytes)\n        {\n            var headerBytes = Encoding.UTF8.GetBytes($\"blob {bytes.Length}\\0\");\n            using var sha1 = SHA1.Create();","sourceCodeStart":463,"sourceCodeEnd":499,"githubUrl":"https://github.com/CoplayDev/unity-mcp/blob/c21bf496bca87d54e75bad048563c3adb1782081/MCPForUnity/Editor/Setup/SkillSyncService.cs#L463-L499","documentation":"ValidateFileHashes computes the git blob SHA1 of each synced local file and compares it to the remote blob SHA from the tree. A mismatch means the on-disk bytes differ from what GitHub served, indicating corruption or unwanted modification.","triggerScenarios":"Line-ending conversion (CRLF vs LF) altered the bytes; a download was truncated/corrupted; an editor or formatter rewrote the file after write; a sync hook injected content.","commonSituations":"Unity or an IDE normalizes line endings on save; .gitattributes eol rules differ; a partial write left truncated content; encoding conversion on copy.","solutions":["Disable automatic line-ending/formatting on the install directory.","Re-run the sync to re-download the file cleanly.","Verify the file is not being rewritten by an editor or sync agent (OneDrive).","For text files, confirm LF line endings are preserved end-to-end."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Disable automatic line-ending normalization on the install directory.","Re-run the sync if a mismatch appears once (clears transient corruption).","Ensure no editor/formatter rewrites files inside the install dir."],"tags":["validation","hash","line-endings"],"backgroundTag":null,"analyzedSha":"c21bf496bca87d54e75bad048563c3adb1782081","analyzedAt":"2026-08-13T17:36:56.095Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}