{"record":{"id":"afb09c6c1c652a05","repo":"crowdsecurity/crowdsec","slug":"client-not-initialized","errorCode":null,"errorMessage":"client not initialized","messagePattern":"client not initialized","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/apiclient/client.go","lineNumber":147,"sourceCode":"\t\treturn fmt.Errorf(\"authenticate watcher (%s): %w\", login, err)\n\t}\n\n\tvar expiration time.Time\n\tif err := expiration.UnmarshalText([]byte(authResp.Expire)); err != nil {\n\t\treturn fmt.Errorf(\"unable to parse jwt expiration: %w\", err)\n\t}\n\n\tclient.GetClient().Transport.(*JWTTransport).Token = authResp.Token\n\tclient.GetClient().Transport.(*JWTTransport).Expiration = expiration\n\n\tlapiClient = client\n\n\treturn nil\n}\n\nfunc GetLAPIClient() (*ApiClient, error) {\n\tif lapiClient == nil {\n\t\treturn nil, errors.New(\"client not initialized\")\n\t}\n\n\treturn lapiClient, nil\n}\n\nfunc NewClient(config *Config) *ApiClient {\n\tuserAgent := config.UserAgent\n\tif userAgent == \"\" {\n\t\tuserAgent = useragent.Default()\n\t}\n\n\tt := &JWTTransport{\n\t\tMachineID:      &config.MachineID,\n\t\tPassword:       &config.Password,\n\t\tUserAgent:      userAgent,\n\t\tVersionPrefix:  config.VersionPrefix,\n\t\tUpdateScenario: config.UpdateScenario,\n\t\tRetryConfig: NewRetryConfig(","sourceCodeStart":129,"sourceCodeEnd":165,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/apiclient/client.go#L129-L165","documentation":"GetLAPIClient returns the package-level LAPI client created by an earlier initialization call. If that initialization never ran (or ran only in another process), the singleton is nil and the accessor fails rather than returning a nil client.","triggerScenarios":"Calling GetLAPIClient before any init function that assigns lapiClient (e.g. before crowdsec's configuration loading), or in a separate binary/tool that never performed LAPI setup.","commonSituations":"Custom integrations importing apiclient and fetching the client at init time before config is parsed; tests that call GetLAPIClient without NewClient/initialization; calling from a code path (like unregisterWatcher) that runs when LAPI is disabled in config.","solutions":["Ensure the client is initialized (config load / NewClient path) before calling GetLAPIClient","In standalone code, create the client explicitly with apiclient.NewClient(&Config{...}) instead of the singleton","Skip or guard LAPI-dependent calls when LAPI is disabled in the configuration"],"exampleFix":"// before\nclient, err := apiclient.GetLAPIClient()\n// after\nclient, err := apiclient.GetLAPIClient()\nif err != nil {\n    client = apiclient.NewClient(cfg) // or return/skip: LAPI not initialized\n}","handlingStrategy":"try-catch","validationCode":"// Go: check initialization state before depending on the singleton\n// ensure the config-load path that sets lapiClient has already run\nclient, err := apiclient.GetLAPIClient()\nif err != nil {\n    client = apiclient.NewClient(cfg) // explicit fallback\n}","typeGuard":null,"tryCatchPattern":"client, err := apiclient.GetLAPIClient()\nif err != nil {\n    return fmt.Errorf(\"LAPI client unavailable (not initialized): %w\", err)\n}","preventionTips":["Initialize the LAPI client during application startup, before any worker goroutine","Prefer explicitly constructed clients (NewClient) over package singletons in tools/tests","Guard LAPI-dependent features behind config flags (e.g. api.enabled)"],"tags":["lapi","apiclient","initialization","state"],"backgroundTag":"missing-dependency","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}