{"record":{"id":"00a58c2272b69c6f","repo":"OpenRA/OpenRA","slug":"cursor-kv-value-name-start-is-greater-than-the","errorCode":null,"errorMessage":"Cursor {kv.Value.Name}: Start is greater than the length of the sprite sequence.","messagePattern":"Cursor (.+?): Start is greater than the length of the sprite sequence\\.","errorType":"exception","errorClass":"YamlException","httpStatus":null,"severity":"error","filePath":"OpenRA.Game/Graphics/CursorManager.cs","lineNumber":65,"sourceCode":"\t\t\tSheetBuilder = new SheetBuilder(SheetType.BGRA, modData.Manifest.RendererConstants.CursorSheetSize);\n\n\t\t\t// Overwrite previous definitions if there are duplicates\n\t\t\tvar pals = new Dictionary<string, IProvidesCursorPaletteInfo>();\n\t\t\tforeach (var p in modData.DefaultRules.Actors[SystemActors.World].TraitInfos<IProvidesCursorPaletteInfo>())\n\t\t\t\tif (p.Palette != null)\n\t\t\t\t\tpals[p.Palette] = p;\n\n\t\t\tvar paletteCache = new Cache<string, ImmutablePalette>(p => pals[p].ReadPalette(modData.DefaultFileSystem));\n\t\t\tvar frameCache = new FrameCache(modData.DefaultFileSystem, modData.SpriteLoaders);\n\n\t\t\t// Sort the cursors for better packing onto the sheet.\n\t\t\tforeach (var kv in modData.Cursors)\n\t\t\t{\n\t\t\t\tvar cursorSprites = frameCache[kv.Value.Src];\n\t\t\t\tvar length = kv.Value.Length ?? cursorSprites.Length - kv.Value.Start;\n\n\t\t\t\tif (kv.Value.Start > cursorSprites.Length)\n\t\t\t\t\tthrow new YamlException($\"Cursor {kv.Value.Name}: {nameof(kv.Value.Start)} is greater than the length of the sprite sequence.\");\n\n\t\t\t\tif (kv.Value.Length > cursorSprites.Length)\n\t\t\t\t\tthrow new YamlException($\"Cursor {kv.Value.Name}: {nameof(kv.Value.Length)} is greater than the length of the sprite sequence.\");\n\n\t\t\t\tvar frames = cursorSprites.Skip(kv.Value.Start).Take(length).ToArray();\n\t\t\t\tvar palette = !string.IsNullOrEmpty(kv.Value.Palette) ? paletteCache[kv.Value.Palette] : null;\n\n\t\t\t\tvar c = new Cursor\n\t\t\t\t{\n\t\t\t\t\tName = kv.Key,\n\t\t\t\t\tBounds = Rectangle.FromLTRB(0, 0, 1, 1),\n\n\t\t\t\t\tLength = 0,\n\t\t\t\t\tSprites = new Sprite[frames.Length],\n\t\t\t\t\tCursors = new IHardwareCursor[frames.Length]\n\t\t\t\t};\n\n\t\t\t\t// Hardware cursors have a number of odd platform-specific bugs/limitations.","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/OpenRA/OpenRA/blob/a520984d91eda9de48a62b1d15c1e3bad0d4fb1a/OpenRA.Game/Graphics/CursorManager.cs#L47-L83","documentation":"Thrown by CursorManager while building hardware/software cursors from the mod's cursor YAML. The CursorSequence's 'Start' field names a zero-based offset into the sprite file, and the engine verifies Start does not exceed the number of frames the loader actually returned (cursorSprites.Length). When Start is greater than that frame count the sequence would begin past the end of the file, so loading aborts with a YamlException rather than producing an empty/broken cursor.","triggerScenarios":"Produced by CursorManager's constructor loop over modData.Cursors: 'if (kv.Value.Start > cursorSprites.Length) throw'. Any cursor sequence whose Src sprite yields fewer frames than the declared Start value triggers it during mod load.","commonSituations":"Cursor YAML points Start at a frame index that does not exist in the .shp/.png sprite (off-by-one, or the sprite was replaced with a shorter one). Renumbering frames after editing a sprite sheet, or copying a cursor definition from another mod whose sprite has a different frame count.","solutions":["Open the sprite file referenced by the cursor's Src and count its frames; set Start to a value at or below that count (Start == length is accepted but yields zero frames, so prefer strictly less).","If Start is correct, replace Src with a sprite file that actually contains at least Start+1 frames.","Run 'OpenRA.Utility <mod> --check-cursors' (or the mod's validation utility) to flag out-of-range Start values before launching the game."],"exampleFix":"# cursor.yaml (before)\ncursor:\n  Src: bits/cursor.shp\n  Start: 12\n# the .shp only has 8 frames -> reduce Start\n# cursor.yaml (after)\ncursor:\n  Src: bits/cursor.shp\n  Start: 4","handlingStrategy":"validation","validationCode":"// Before relying on a cursor sequence, verify Start against the sprite frame count.\nvar frames = frameCache[cursorSeq.Src];\nif (cursorSeq.Start > frames.Length)\n    throw new InvalidOperationException($\"Cursor {cursorSeq.Name}: Start {cursorSeq.Start} exceeds {frames.Length} frames in {cursorSeq.Src}\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Run the mod's cursor validation utility after editing any cursor YAML or sprite.","Keep Start and Length documented next to each sprite's actual frame count.","Treat Start == frames.Length as a smell even though it is permitted (it yields zero frames)."],"tags":["yaml","cursor","sprite","config","load-time"],"backgroundTag":null,"analyzedSha":"a520984d91eda9de48a62b1d15c1e3bad0d4fb1a","analyzedAt":"2026-08-13T15:30:14.787Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}