{"record":{"id":"7e3dd1ca087d21c9","repo":"crowdsecurity/crowdsec","slug":"leaky-bucketconfig-is-nil","errorCode":null,"errorMessage":"leaky.BucketConfig is nil","messagePattern":"leaky\\.BucketConfig is nil","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/leakybucket/overflows.go","lineNumber":341,"sourceCode":"\tscenarioHash := leaky.Factory.scenarioHash\n\tscenarioVersion := leaky.Factory.Spec.ScenarioVersion\n\tsimulated := leaky.Factory.Simulated\n\tapiAlert := models.Alert{\n\t\tScenario:        &scenario,\n\t\tScenarioHash:    &scenarioHash,\n\t\tScenarioVersion: &scenarioVersion,\n\t\tCapacity:        &capacity,\n\t\tEventsCount:     &EventsCount,\n\t\tLeakspeed:       &leakSpeed,\n\t\tMessage:         new(string),\n\t\tStartAt:         &startAt,\n\t\tStopAt:          &stopAt,\n\t\tSimulated:       &simulated,\n\t\tKind:            types.CrowdsecAlertKind.String(),\n\t}\n\n\tif leaky.Factory == nil {\n\t\treturn runtimeAlert, errors.New(\"leaky.BucketConfig is nil\")\n\t}\n\n\t// give information about the bucket\n\truntimeAlert.Mapkey = leaky.Mapkey\n\n\t// Get the sources from Leaky/Queue\n\tsources, source_scope, err := alertFormatSource(leaky, queue)\n\tif err != nil {\n\t\treturn runtimeAlert, fmt.Errorf(\"unable to collect sources from bucket: %w\", err)\n\t}\n\n\truntimeAlert.Sources = sources\n\t// Include source info in format string\n\tsourceStr := \"UNKNOWN\"\n\tif len(sources) > 1 {\n\t\tsourceStr = fmt.Sprintf(\"%d sources\", len(sources))\n\t} else if len(sources) == 1 {\n\t\tfor k := range sources {","sourceCodeStart":323,"sourceCodeEnd":359,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/leakybucket/overflows.go#L323-L359","documentation":"NewAlert builds an overflow alert from a leaky bucket; it requires leaky.Factory (the BucketConfig) to be set because the alert carries bucket metadata. A nil Factory means the bucket holder was mis-initialized, so alert construction is refused.","triggerScenarios":"Calling NewAlert on a Leaky whose Factory field was never assigned (bucket holder created without a factory), before extracting sources.","commonSituations":"Custom Go code or tests constructing a Leaky struct directly without Build/BucketFactory wiring, or a regression in bucket initialization order.","solutions":["Ensure buckets are created through the normal LoadOrStoreBucketFromHolder/Build pipeline so Factory is populated","In custom code, assign the BucketFactory to leaky.Factory before calling NewAlert","Check initialization order in tests (TestAlertDoesNotShareStringsWithFactory constructs holders manually)"],"exampleFix":"// before\nleaky := &leakybucket.Leaky{}\nalert, err := leaky.NewAlert(evt)\n// after\nleaky := &leakybucket.Leaky{Factory: bucketFactory}\nalert, err := leaky.NewAlert(evt)","handlingStrategy":"type-guard","validationCode":"if leaky.Factory == nil {\n    return errors.New(\"bucket holder not initialized: Factory missing before NewAlert\")\n}","typeGuard":"func factoryReady(l *leakybucket.Leaky) bool { return l != nil && l.Factory != nil }","tryCatchPattern":"if alert, err := leaky.NewAlert(evt); err != nil {\n    if err.Error() == \"leaky.BucketConfig is nil\" {\n        return fmt.Errorf(\"bucket %s mis-initialized (no factory)\", leaky.Mapkey)\n    }\n    return err\n}","preventionTips":["Create buckets only via the standard Build/load pipeline","In tests, always wire a BucketFactory into the Leaky struct","Check bucket init order after refactorings"],"tags":["crowdsec","leakybucket","nil-pointer","alert"],"backgroundTag":"null-argument","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}