{"id":"26b57b7c80f0e056","repo":"docker/cli","slug":"error-registering-pruner-prune-function-is-nil-fo","errorCode":null,"errorMessage":"error registering pruner: prune function is nil for %s","messagePattern":"error registering pruner: prune function is nil for (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/command/system/pruner/pruner.go","lineNumber":103,"sourceCode":"\n// Register registers a [PruneFunc] under the given name to be included in\n// \"docker system prune\". It is designed to be called in an init function\n// and is not safe for concurrent use.\n//\n// For example:\n//\n//\t func init() {\n//\t\t// Register the prune command to run as part of \"docker system prune\".\n//\t\tif err := prune.Register(prune.TypeImage, prunerFn); err != nil {\n//\t\t\tpanic(err)\n//\t\t}\n//\t}\nfunc Register(name ContentType, pruneFunc PruneFunc) error {\n\tif name == \"\" {\n\t\treturn errors.New(\"error registering pruner: invalid prune type: cannot be empty\")\n\t}\n\tif pruneFunc == nil {\n\t\treturn errors.New(\"error registering pruner: prune function is nil for \" + string(name))\n\t}\n\tif registered == nil {\n\t\tregistered = make(map[ContentType]PruneFunc)\n\t}\n\tif _, exists := registered[name]; exists {\n\t\treturn fmt.Errorf(\"error registering pruner: content-type %s is already registered\", name)\n\t}\n\tregistered[name] = pruneFunc\n\treturn nil\n}\n\n// List iterates over all registered pruners, starting with known pruners\n// in their predefined order, followed by any others (sorted alphabetically).\nfunc List() iter.Seq2[ContentType, PruneFunc] {\n\tall := maps.Clone(registered)\n\tordered := make([]ContentType, 0, len(all))\n\tfor _, ct := range pruneOrder {\n\t\tif _, ok := all[ct]; ok {","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/docker/cli/blob/e9452d6e785f6e365712b9d71bd7517591773c86/cli/command/system/pruner/pruner.go#L85-L121","documentation":"Returned by pruner.Register when a nil PruneFunc is passed for the given content type. Since registered pruners are invoked directly by `docker system prune`, a nil function would panic at prune time, so registration rejects it up front.","triggerScenarios":"Calling pruner.Register(name, nil) from an init() function — e.g. passing a function variable that hasn't been assigned yet due to package initialization order, at cli/command/system/pruner/pruner.go:103.","commonSituations":"Fork/extension authors passing a nil function pointer; init-order bugs where the PruneFunc variable is populated after the Register call runs. Not reachable through normal docker CLI usage — it is a defensive check against programming errors.","solutions":["Pass a concrete, non-nil PruneFunc at registration time.","If the function is assigned elsewhere, restructure so Register is called after assignment (or register a closure that resolves the implementation at call time)."],"exampleFix":"// before\nvar pruneFn pruner.PruneFunc // nil at init time\nfunc init() { _ = pruner.Register(pruner.TypeImage, pruneFn) }\n// after\nfunc init() {\n    _ = pruner.Register(pruner.TypeImage, func(ctx context.Context, cli command.Cli, opts pruner.Options) (uint64, string, error) {\n        return runImagePrune(ctx, cli, opts)\n    })\n}","handlingStrategy":null,"validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":["docker-cli","pruner","nil-function","developer-error"],"analyzedSha":"e9452d6e785f6e365712b9d71bd7517591773c86","analyzedAt":"2026-08-01T07:09:22.474Z","schemaVersion":2}