{"record":{"id":"1410ab4a369f0958","repo":"stride3d/stride","slug":"truncated-cache-indirection-file","errorCode":null,"errorMessage":"Truncated cache indirection file","messagePattern":"Truncated cache indirection file","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/shaders/Stride.Shaders.Effects/Compiler/EffectCompilerCache.cs","lineNumber":150,"sourceCode":"                // 2.5) Try to load from application cache (DynamicCache entries)\n                //      Uses indirection: {effectInputHash}.cache contains the output hash,\n                //      then {outputHash} contains the actual bytecode (shared across inputs with same output).\n                // ------------------------------------------------------------------------------------------------------------\n                if (bytecode.Key == null)\n                {\n                    var indirectionPath = GetAppCacheIndirectionPath(mixin.Name, effectInputHash);\n                    if (VirtualFileSystem.ApplicationCache.FileExists(indirectionPath))\n                    {\n                        try\n                        {\n                            // Read the output hash from the indirection file\n                            ObjectId outputHash;\n                            using (var indirStream = VirtualFileSystem.ApplicationCache.OpenStream(\n                                indirectionPath, VirtualFileMode.Open, VirtualFileAccess.Read, VirtualFileShare.Read))\n                            {\n                                var outputHashBuffer = new byte[ObjectId.HashSize];\n                                if (indirStream.Read(outputHashBuffer, 0, ObjectId.HashSize) != ObjectId.HashSize)\n                                    throw new InvalidOperationException(\"Truncated cache indirection file\");\n                                outputHash = new ObjectId(outputHashBuffer);\n                            }\n\n                            // Load bytecode from the shared output file\n                            var bytecodePath = GetAppCachePath(mixin.Name, outputHash);\n                            if (VirtualFileSystem.ApplicationCache.FileExists(bytecodePath))\n                            {\n                                using var stream = VirtualFileSystem.ApplicationCache.OpenStream(\n                                    bytecodePath, VirtualFileMode.Open, VirtualFileAccess.Read, VirtualFileShare.Read);\n                                var loadedBytecode = EffectBytecode.FromStream(stream);\n                                if (loadedBytecode != null && !IsBytecodeObsolete(loadedBytecode))\n                                {\n                                    bytecode = new KeyValuePair<EffectBytecode, EffectBytecodeCacheLoadSource>(\n                                        loadedBytecode, EffectBytecodeCacheLoadSource.DynamicCache);\n                                    bytecodes[outputHash] = bytecode;\n                                }\n                            }\n                        }","sourceCodeStart":132,"sourceCodeEnd":168,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/shaders/Stride.Shaders.Effects/Compiler/EffectCompilerCache.cs#L132-L168","documentation":"While loading bytecode through the shared application cache, the indirection file should contain exactly one ObjectId (the output hash). If the stream yields fewer bytes than ObjectId.HashSize, the cache considers the indirection file corrupt/truncated and throws InvalidOperationException instead of loading garbage.","triggerScenarios":"The ApplicationCache indirection file exists but is shorter than ObjectId.HashSize — typically from an interrupted write, disk-full condition, crash mid-write, or a partially synced cache directory.","commonSituations":"Killed builds/processes leaving partial cache files; shared/roaming cache folders synced incompletely; manual copying of cache directories.","solutions":["Delete the truncated indirection file (and the stale app cache directory) so it is regenerated on next compile.","Clear VirtualFileSystem.ApplicationCache contents and rebuild/recompile effects.","Ensure cache writes complete atomically (write temp + rename) in environments prone to interruption."],"exampleFix":"// before\nvar hash = LoadIndirection(path); // throws: Truncated cache indirection file\n// after\nif (!File.Exists(indirectionPath) || new FileInfo(indirectionPath).Length < ObjectId.HashSize)\n    File.Delete(indirectionPath); // force regeneration, then retry compile","handlingStrategy":"try-catch","validationCode":"using (var s = VirtualFileSystem.ApplicationCache.OpenStream(indirectionPath, VirtualFileMode.Open, VirtualFileAccess.Read)) if (s.Length < ObjectId.HashSize) { /* treat cache entry as corrupt: delete and recompile */ }","typeGuard":"null","tryCatchPattern":"try { bytecode = LoadFromCache(hash); } catch (InvalidOperationException ex) when (ex.Message == \"Truncated cache indirection file\") { InvalidateCacheEntry(); result = RecompileEffect(); }","preventionTips":["Write cache files atomically (temp file + rename)","Clear the application cache after interrupted builds","Avoid sharing a live cache directory over sync tools","Monitor cache directory for zero/partial-size files"],"tags":["cache","corruption","file-io"],"backgroundTag":"file-read-failed","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}