{"record":{"id":"7deb996fee362169","repo":"SixLabors/ImageSharp","slug":"frame-quantizer-palette-has-not-been-built","errorCode":null,"errorMessage":"Frame Quantizer palette has not been built.","messagePattern":"Frame Quantizer palette has not been built\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs","lineNumber":160,"sourceCode":"        }\n    }\n\n    /// <summary>\n    /// Helper method for throwing an exception when a frame quantizer palette has\n    /// been requested but not built yet.\n    /// </summary>\n    /// <typeparam name=\"TPixel\">The pixel format.</typeparam>\n    /// <param name=\"palette\">The frame quantizer palette.</param>\n    /// <exception cref=\"InvalidOperationException\">\n    /// The palette has not been built via <see cref=\"IQuantizer{TPixel}.AddPaletteColors(in Buffer2DRegion{TPixel})\"/>\n    /// </exception>\n    [MethodImpl(InliningOptions.ColdPath)]\n    public static void CheckPaletteState<TPixel>(in ReadOnlyMemory<TPixel> palette)\n        where TPixel : unmanaged, IPixel<TPixel>\n    {\n        if (palette.IsEmpty)\n        {\n            throw new InvalidOperationException(\"Frame Quantizer palette has not been built.\");\n        }\n    }\n\n    /// <summary>\n    /// Execute both steps of the quantization.\n    /// </summary>\n    /// <param name=\"quantizer\">The pixel specific quantizer.</param>\n    /// <param name=\"source\">The source image frame to quantize.</param>\n    /// <param name=\"bounds\">The bounds within the frame to quantize.</param>\n    /// <typeparam name=\"TPixel\">The pixel type.</typeparam>\n    /// <returns>\n    /// A <see cref=\"IndexedImageFrame{TPixel}\"/> representing a quantized version of the source frame pixels.\n    /// </returns>\n    public static IndexedImageFrame<TPixel> BuildPaletteAndQuantizeFrame<TPixel>(\n        this IQuantizer<TPixel> quantizer,\n        ImageFrame<TPixel> source,\n        Rectangle bounds)\n        where TPixel : unmanaged, IPixel<TPixel>","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/SixLabors/ImageSharp/blob/59ce6af6fc29027cda277ef62d4d1694a8acce91/src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs#L142-L178","documentation":"CheckPaletteState is a preconditions helper called before quantization output is written; it requires that the frame quantizer's palette has already been produced by a prior BuildPalette step. An empty palette means the two-phase quantization protocol was not followed, so the library cannot map pixels. It throws InvalidOperationException to indicate a caller sequencing bug rather than bad input data.","triggerScenarios":"Calling AddFrameToPalette or palette-consuming quantization APIs with a quantizer whose palette memory is empty, i.e. skipping ExecuteQuantization's palette build phase or calling the second phase first.","commonSituations":"Implementing a custom IFrameQuantizer that forgets to assign the palette; calling quantizer methods out of order when writing custom encoders; refactorings that removed the BuildPalette call before quantization.","solutions":["Ensure quantizer.BuildPalette (or QuantizerUtilities.BuildPalette) is called before consuming the palette","If implementing a custom IFrameQuantizer, set the palette in BuildPalette and only use it after","Use QuantizerUtilities.ExecuteQuantization to run both steps in the correct order instead of calling phases manually"],"exampleFix":"// before\nvar quantizer = new OctreeQuantizer();\nvar quantized = quantizer.QuantizeFrame(image.Frames[0], out var palette); // palette never built\n// after\nusing var quantizer = new OctreeQuantizer();\nusing var paletteBuilt = quantizer.BuildPalette(image.Frames[0]);\nvar quantized = quantizer.QuantizeFrame(image.Frames[0], paletteBuilt, out var palette);","handlingStrategy":"validation","validationCode":"// Ensure palette is built before consuming:\n// var palette = quantizer.BuildPalette(frame); // non-empty ReadOnlyMemory<TPixel>\n// Then call quantize with the built palette.","typeGuard":"static bool HasPalette<TPixel>(ReadOnlyMemory<TPixel> p) where TPixel : unmanaged, IPixel<TPixel> => !p.IsEmpty;","tryCatchPattern":"try\n{\n    // palette-consuming quantization call\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"palette has not been built\"))\n{\n    // call BuildPalette first, then retry\n    throw;\n}","preventionTips":["Call BuildPalette (or ExecuteQuantization) before accessing any palette-dependent quantization result","When implementing IFrameQuantizer, assign the palette inside BuildPalette and document the required order","Prefer QuantizerUtilities.ExecuteQuantization over manual two-phase calls","Add a debug assertion or unit test verifying palette non-emptiness before quantize"],"tags":["quantization","palette","invalid-state"],"backgroundTag":"invalid-state-transition","analyzedSha":"59ce6af6fc29027cda277ef62d4d1694a8acce91","analyzedAt":"2026-09-13T18:34:59.331Z","contentChangedAt":"2026-09-13T18:34:59.331Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}