{"record":{"id":"c345f9694e40d8cc","repo":"LorisYounger/VPet","slug":"no-apng-frames-found","errorCode":null,"errorMessage":"No APNG frames found.","messagePattern":"No APNG frames found\\.","errorType":"exception","errorClass":"InvalidDataException","httpStatus":null,"severity":"error","filePath":"VPet-Simulator.Core/Graph/APNGAnimation.cs","lineNumber":121,"sourceCode":"        private async Task startup()\n        {\n            while (Function.MemoryUsage() > PNGAnimation.MaxLoadMemory)\n            {\n                await Task.Delay(100);\n            }\n\n            try\n            {\n                if (!File.Exists(Path))\n                    throw new FileNotFoundException($\"Can not find file: {Path}\");\n\n                IsReady = false;\n                IsFail = false;\n                FailMessage = \"\";\n\n                var parsed = ParseApng(Path);\n                if (parsed.Frames.Count == 0)\n                    throw new InvalidDataException(\"No APNG frames found.\");\n\n                FrameWidth = parsed.CanvasWidth;\n                FrameHeight = parsed.CanvasHeight;\n                if (FrameWidth > GraphCore.Resolution)\n                {\n                    FrameWidth = GraphCore.Resolution;\n                    FrameHeight = (int)(FrameHeight * (GraphCore.Resolution / (double)parsed.CanvasWidth));\n                }\n                if (parsed.Frames.Count * FrameWidth >= 60000)\n                {\n                    FrameWidth = 60000 / parsed.Frames.Count;\n                    FrameHeight = (int)(parsed.CanvasHeight * (FrameWidth / (double)parsed.CanvasWidth));\n                }\n\n                FrameRects = new Int32Rect[parsed.Frames.Count];\n                lock (FrameCacheLock)\n                {\n                    FrameCache.Clear();","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/LorisYounger/VPet/blob/ffb9cc2a856244a0f91aa5ecf10d097bcdd4954f/VPet-Simulator.Core/Graph/APNGAnimation.cs#L103-L139","documentation":"After ParseApng succeeds structurally, the loader requires at least one animation frame; a parsed PNG with zero frames is rejected with InvalidDataException. This catches files that are valid static PNGs (or APNGs with no fcTL/frame chunks) being used as animations.","triggerScenarios":"Passing a plain (non-animated) PNG or a truncated APNG with no fcTL chunks as Path to APNGAnimation; ParseApng returns an empty Frames list.","commonSituations":"Modder replaces an animated background with a static PNG; download truncation strips animation chunks; image editor re-save strips APNG acTL/fcTL chunks.","solutions":["Supply an actual APNG file containing acTL and at least one fcTL/fdAT sequence.","Re-export the animation as APNG (e.g. ffmpeg or apngasm) instead of a static PNG.","Check the file was not re-saved by a tool that drops animation chunks.","Fall back to a static Graph/Picture handler if the image is intentionally non-animated."],"exampleFix":"// before\nnew APNGAnimation(\"logo.png\"); // static PNG\n// after\nusing var fs = File.OpenRead(path);\n// verify acTL/fcTL chunks or convert:\n// ffmpeg -i logo.png -plays 0 logo_apng.png","handlingStrategy":"validation","validationCode":"using var fs = File.OpenRead(path);\nvar data = new byte[8]; fs.Read(data,0,8);\nbool hasActl = false; /* scan chunk types for \"acTL\"+\"fcTL\" before loading */","typeGuard":null,"tryCatchPattern":"try { var anim = new APNGAnimation(path); } catch (InvalidDataException) { UseStaticImage(path); }","preventionTips":["Never re-save APNG assets in editors that drop ancillary chunks","Distinguish static PNGs (Graph/Picture) from APNGs (Graph/APNGAnimation) at load time","Keep animations in APNG format from the source tool"],"tags":["png","animation","validation"],"backgroundTag":"empty-required-field","analyzedSha":"ffb9cc2a856244a0f91aa5ecf10d097bcdd4954f","analyzedAt":"2026-09-15T21:21:10.398Z","contentChangedAt":"2026-09-15T21:21:10.398Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}