{"record":{"id":"871e62c199006fbd","repo":"crowdsecurity/crowdsec","slug":"loading-cti-configuration-w","errorCode":null,"errorMessage":"loading CTI configuration: %w","messagePattern":"loading CTI configuration: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/csconfig/api.go","lineNumber":439,"sourceCode":"\tif c.API.Server.TrustedProxies != nil {\n\t\tc.API.Server.UseForwardedForHeaders = true\n\t}\n\n\tif err := c.API.Server.LoadProfiles(); err != nil {\n\t\treturn fmt.Errorf(\"while loading profiles for LAPI: %w\", err)\n\t}\n\n\tif c.API.Server.ConsoleConfigPath == \"\" {\n\t\tc.API.Server.ConsoleConfigPath = DefaultConsoleConfigFilePath\n\t}\n\n\tif err := c.API.Server.LoadConsoleConfig(); err != nil {\n\t\treturn fmt.Errorf(\"while loading console options: %w\", err)\n\t}\n\n\tif c.API.CTI != nil {\n\t\tif err := c.API.CTI.Load(); err != nil {\n\t\t\treturn fmt.Errorf(\"loading CTI configuration: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// we cannot unmarshal to type net.IPNet, so we need to do it manually\ntype capiWhitelists struct {\n\tIps   []string `yaml:\"ips\"`\n\tCidrs []string `yaml:\"cidrs\"`\n}\n\nfunc parseCapiWhitelists(fd io.Reader) (*CapiWhitelist, error) {\n\tfromCfg := capiWhitelists{}\n\n\tdecoder := yaml.NewDecoder(fd)\n\tif err := decoder.Decode(&fromCfg); err != nil {\n\t\tif errors.Is(err, io.EOF) {","sourceCodeStart":421,"sourceCodeEnd":457,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/csconfig/api.go#L421-L457","documentation":"When an api.cti section is present in config.yaml, LoadAPIServer calls CTI.Load(), and any failure (typically a missing/empty API key or invalid key format) is wrapped with this prefix. The CTI section integrates CrowdSec Threat Intelligence lookups into the console.","triggerScenarios":"crowdsec startup with `api.cti` defined in config.yaml but cti.key empty, or key not matching the expected format enforced by CTI.Load().","commonSituations":"User enabled the CTI block after copying an example config without inserting their CrowdSec CTI API key; key revoked/typo'd; running key validation during config load fails.","solutions":["Set a valid key under api.cti.key in config.yaml","Remove or comment out the whole api.cti section if you don't use CTI key sharing","Get/renew a key from the CrowdSec CTI console page","Check the wrapped inner error for the exact validation failure"],"exampleFix":"// before (config.yaml)\napi:\n  cti:\n    enabled: true\n    key: \"\"\n// after\napi:\n  cti:\n    enabled: true\n    key: \"<your-cti-api-key>\"","handlingStrategy":"validation","validationCode":"// before enabling CTI, ensure the key is set and non-empty\nif cti != nil && cti.Key == \"\" {\n\treturn errors.New(\"api.cti enabled but key is empty — get one at the CTI console\")\n}","typeGuard":null,"tryCatchPattern":"if err := cfg.LoadAPIServer(); err != nil {\n\tif strings.Contains(err.Error(), \"CTI configuration\") {\n\t\tlog.Warnf(\"CTI disabled due to config problem: %v\", err)\n\t\tcfg.API.CTI = nil\n\t\treturn nil\n\t}\n\treturn err\n}","preventionTips":["Only add the api.cti block after obtaining a real key from the CTI dashboard","Never commit a config with an empty key field","Remove the whole cti block rather than leaving it half-filled"],"tags":["config","cti","api-key","lapi"],"backgroundTag":"missing-api-key","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"}