{"record":{"id":"dab00e646c101997","repo":"gohugoio/hugo","slug":"palette-must-have-at-least-two-colors","errorCode":null,"errorMessage":"palette must have at least two colors","messagePattern":"palette must have at least two colors","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"resources/images/filters.go","lineNumber":228,"sourceCode":"\t}{\n\t\tMethod:     \"floydsteinberg\",\n\t\tSerpentine: true,\n\t\tStrength:   1.0,\n\t}\n\n\tif len(options) != 0 {\n\t\terr := mapstructure.WeakDecode(options[0], &ditherOptions)\n\t\tif err != nil {\n\t\t\tpanic(fmt.Sprintf(\"failed to decode options: %s\", err))\n\t\t}\n\t}\n\n\tif len(ditherOptions.Colors) == 0 {\n\t\tditherOptions.Colors = []any{\"000000ff\", \"ffffffff\"}\n\t}\n\n\tif len(ditherOptions.Colors) < 2 {\n\t\tpanic(\"palette must have at least two colors\")\n\t}\n\n\tvar palette []color.Color\n\tfor _, c := range ditherOptions.Colors {\n\t\tcc, ok, err := toColorGo(c)\n\t\tif !ok || err != nil {\n\t\t\tpanic(fmt.Sprintf(\"%q is an invalid color: specify RGB or RGBA using hexadecimal notation\", c))\n\t\t}\n\t\tpalette = append(palette, cc)\n\t}\n\n\td := dither.NewDitherer(palette)\n\tif method, ok := ditherMethodsErrorDiffusion[strings.ToLower(ditherOptions.Method)]; ok {\n\t\td.Matrix = dither.ErrorDiffusionStrength(method, ditherOptions.Strength)\n\t\td.Serpentine = ditherOptions.Serpentine\n\t} else if method, ok := ditherMethodsOrdered[strings.ToLower(ditherOptions.Method)]; ok {\n\t\td.Mapper = dither.PixelMapperFromMatrix(method, ditherOptions.Strength)\n\t} else {","sourceCodeStart":210,"sourceCodeEnd":246,"githubUrl":"https://github.com/gohugoio/hugo/blob/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/resources/images/filters.go#L210-L246","documentation":"Thrown by images.Dither when the palette has fewer than two colors (filters.go:223-229). Note the filter seeds a default two-color palette when Colors is empty, so this only fires when exactly one color is supplied — dithering requires at least two to be meaningful.","triggerScenarios":"Passing a Colors slice with exactly one element, e.g. (dict \"Colors\" (slice \"000000ff\")). Empty Colors is safe (defaults applied); one color is rejected.","commonSituations":"Developer wants a monochrome look and lists only black, forgetting the white counterpart; or a conditional slice construction ends up with a single element.","solutions":["Provide at least two palette colors.","If you want defaults, omit Colors entirely rather than passing one value.","Guard dynamic palette slices to ensure length >= 2."],"exampleFix":"// before\n{{ $filters = $filters | append (images.Dither (dict \"Colors\" (slice \"000000ff\"))) }}\n// after\n{{ $filters = $filters | append (images.Dither (dict \"Colors\" (slice \"000000ff\" \"ffffffff\"))) }}","handlingStrategy":"validation","validationCode":"{{ $colors := .colors | default (slice \"000000ff\" \"ffffffff\") }}\n{{ if lt (len $colors) 2 }}{{ errorf \"palette needs >= 2 colors\" }}{{ end }}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Omit Colors to accept the default two-color palette.","When specifying Colors, ensure at least two entries.","Guard dynamically built palettes for length >= 2."],"tags":["image-filter","dither","palette","validation","hugo"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}