{"record":{"id":"50f43e1aa4262745","repo":"cilium/cilium","slug":"registry-has-already-been-started","errorCode":null,"errorMessage":"registry has already been started","messagePattern":"registry has already been started","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/maps/registry/registry.go","lineNumber":22,"sourceCode":"package registry\n\nimport (\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log/slog\"\n\n\t\"github.com/cilium/ebpf\"\n\n\t_ \"github.com/cilium/hive/cell\"\n\n\t\"github.com/cilium/cilium/pkg/datapath/maps\"\n\t\"github.com/cilium/cilium/pkg/lock\"\n\t\"github.com/cilium/cilium/pkg/logging/logfields\"\n)\n\nvar (\n\tErrStarted     = errors.New(\"registry has already been started\")\n\tErrNotStarted  = errors.New(\"registry has not yet been started\")\n\tErrMapNotFound = errors.New(\"MapSpec not found\")\n)\n\n// MapRegistry contains [ebpf.MapSpec]s for all pinned maps in the datapath.\n//\n// The registry allows Cells to provide [MapSpecPatch]es during Hive\n// construction, e.g. for changing MaxEntries of a map based on configuration\n// parameters. Only select fields can be modified, see [MapSpecPatch] for\n// details.\n//\n// Once the registry has been started, MapSpecs can only be retrieved but\n// not modified. Any packages which need to create maps at runtime should\n// obtain the MapSpecs from this registry.\ntype MapRegistry struct {\n\tl *slog.Logger\n\n\tmu      lock.Mutex","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/cilium/cilium/blob/ac7b90affa4baf0642e6685319d56907b3a73a6d/pkg/maps/registry/registry.go#L4-L40","documentation":"ErrStarted is a sentinel error of the pkg/maps/registry MapRegistry. The registry is a Hive cell holding [ebpf.MapSpec]s for all pinned datapath maps; after Start() it becomes read-only because patches must be applied before map pinning. It is returned by start (double start), Modify, and TestMapRegistry to signal that lifecycle transition is no longer permitted.","triggerScenarios":"Calling Start() (or the Hive lifecycle start) twice on the same MapRegistry; calling Modify() or TestMapRegistry() after the registry has been started.","commonSituations":"Duplicated cell registration or a module invoking the registry's lifecycle hook manually in addition to Hive; tests or tooling that fetch/patch maps after agent startup has completed.","solutions":["Reorder code so Start() is invoked exactly once, via Hive rather than manually.","Move all Modify()/TestMapRegistry() calls before registry startup (during Hive construction).","Use errors.Is(err, registry.ErrStarted) to detect and skip an idempotent second start.","Refactor the component to depend on the already-started registry instead of starting its own."],"exampleFix":"// before\nregistry.Start()\n...\nregistry.Start() // panics path with ErrStarted\n// after\nif err := registry.Start(); err != nil {\n    if !errors.Is(err, registry.ErrStarted) { return err } // already started: ok, idempotent\n}","handlingStrategy":"try-catch","validationCode":"// guard before modifying\nif registryStarted(reg) {\n    return fmt.Errorf(\"cannot modify registry after start\")\n}","typeGuard":"func registryStarted(r *registry.MapRegistry) bool {\n    // exposed state check: attempt an operation that is only valid pre-start\n    return r.GetPatch(\"__probe__\") == nil // if lookup works, registry is started\n}","tryCatchPattern":"if err := reg.Modify(patch); err != nil {\n    if errors.Is(err, registry.ErrStarted) {\n        // registry already started: move modification to pre-start phase or ignore\n        return nil\n    }\n    return err\n}","preventionTips":["Only modify the registry during Hive construction, never in Start/PostStart hooks","Start the registry exclusively through the Hive lifecycle to avoid double start","Use errors.Is against registry.ErrStarted for idempotent start paths"],"tags":["go","ebpf","lifecycle","hive"],"backgroundTag":"already-started","analyzedSha":"ac7b90affa4baf0642e6685319d56907b3a73a6d","analyzedAt":"2026-08-31T18:27:15.868Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}