{"record":{"id":"ff16c8106a58e824","repo":"crowdsecurity/crowdsec","slug":"stream-name-is-mandatory-when-use-enhanced-fanout","errorCode":null,"errorMessage":"stream_name is mandatory when use_enhanced_fanout is false","messagePattern":"stream_name is mandatory when use_enhanced_fanout is false","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/acquisition/modules/kinesis/config.go","lineNumber":77,"sourceCode":"\tif c.MaxRetries <= 0 {\n\t\tc.MaxRetries = 10\n\t}\n}\n\nfunc (s *Source) UnmarshalConfig(yamlConfig []byte) error {\n\tcfg, err := ConfigurationFromYAML(yamlConfig)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ts.Config = cfg\n\n\treturn nil\n}\n\nfunc (c *Configuration) Validate() error {\n\tif c.StreamName == \"\" && !c.UseEnhancedFanOut {\n\t\treturn errors.New(\"stream_name is mandatory when use_enhanced_fanout is false\")\n\t}\n\n\tif c.StreamARN == \"\" && c.UseEnhancedFanOut {\n\t\treturn errors.New(\"stream_arn is mandatory when use_enhanced_fanout is true\")\n\t}\n\n\tif c.ConsumerName == \"\" && c.UseEnhancedFanOut {\n\t\treturn errors.New(\"consumer_name is mandatory when use_enhanced_fanout is true\")\n\t}\n\n\tif c.StreamARN != \"\" && c.StreamName != \"\" {\n\t\treturn errors.New(\"stream_arn and stream_name are mutually exclusive\")\n\t}\n\n\treturn nil\n}\n\nfunc (s *Source) Configure(ctx context.Context, yamlConfig []byte, logger *log.Entry, metricsLevel metrics.AcquisitionMetricsLevel) error {","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/acquisition/modules/kinesis/config.go#L59-L95","documentation":"The kinesis acquisition source requires a way to identify the target stream. When use_enhanced_fanout is false, the source reads from the shared stream consumer, which is addressed by stream name, so Configuration.Validate() rejects configs where StreamName is empty. Enhanced fan-out mode instead identifies the stream by ARN, which is why the name is only mandatory in non-fan-out mode.","triggerScenarios":"Calling Validate() on a kinesis Configuration where UseEnhancedFanOut is false (or unset) and StreamName is the empty string.","commonSituations":"A YAML acquisition entry for kinesis that omits the stream_name key, or uses stream_arn alone without enabling use_enhanced_fanout: true. Also happens when stream_name is set via a template/variable that expands to empty.","solutions":["Set stream_name in the kinesis acquisition YAML config (e.g. stream_name: my-log-stream).","If you intended enhanced fan-out mode, set use_enhanced_fanout: true and provide stream_arn (and consumer_name) instead of stream_name.","Run `cscli` acquisition validation or a local Validate() call before deploying to catch this early."],"exampleFix":"// before (yaml)\nsource: kinesis\nstream_arn: arn:aws:kinesis:us-east-1:123456789012:stream/logs\n\n// after (yaml)\nsource: kinesis\nstream_name: logs\n# or, for fan-out:\n# use_enhanced_fanout: true\n# stream_arn: arn:aws:kinesis:us-east-1:123456789012:stream/logs\n# consumer_name: crowdsec-consumer","handlingStrategy":"validation","validationCode":"if cfg.UseEnhancedFanOut == false && cfg.StreamName == \"\" {\n    return fmt.Errorf(\"kinesis: stream_name is required when use_enhanced_fanout is false\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate kinesis acquisition configs with cscli or a Validate() call before deploying.","Keep one config template per mode (shared consumer vs fan-out) so required keys are never omitted.","Never rely on templated/secret variables for stream_name without checking they expand non-empty."],"tags":["aws","kinesis","config-validation","acquisition"],"backgroundTag":"missing-required-config-field","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"}