{"record":{"id":"b7592b9b0cb51432","repo":"crowdsecurity/crowdsec","slug":"no-source-user-in-header-message-skipping","errorCode":null,"errorMessage":"no source user in header message, skipping","messagePattern":"no source user in header message, skipping","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"pkg/apiserver/papi.go","lineNumber":143,"sourceCode":"\n\treturn papi, nil\n}\n\nfunc (p *Papi) handleEvent(ctx context.Context, event longpollclient.Event, sync bool) error {\n\tlogger := p.Logger.WithField(\"request-id\", event.RequestId)\n\tlogger.Debugf(\"message received: %+v\", event.Data)\n\n\tmessage := &Message{}\n\tif err := json.Unmarshal([]byte(event.Data), message); err != nil {\n\t\treturn fmt.Errorf(\"polling papi message format is not compatible: %+v: %w\", event.Data, err)\n\t}\n\n\tif message.Header == nil {\n\t\treturn errors.New(\"no header in message, skipping\")\n\t}\n\n\tif message.Header.Source == nil {\n\t\treturn errors.New(\"no source user in header message, skipping\")\n\t}\n\n\toperationFunc, ok := operationMap[message.Header.OperationType]\n\tif !ok {\n\t\treturn fmt.Errorf(\"operation '%s' unknown, continue\", message.Header.OperationType)\n\t}\n\n\tmetrics.PapiOrdersReceived.WithLabelValues(message.Header.OperationType, message.Header.OperationCmd).Inc()\n\n\tlogger.Debugf(\"Calling operation '%s'\", message.Header.OperationType)\n\n\terr := operationFunc(ctx, message, p, sync)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"'%s %s failed: %w\", message.Header.OperationType, message.Header.OperationCmd, err)\n\t}\n\n\treturn nil\n}","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/apiserver/papi.go#L125-L161","documentation":"A polled message has a Header but its Source field is nil, i.e. the header does not identify which user/service sent it. Since the operation handlers need the source identity, the message is rejected and skipped with this error.","triggerScenarios":"PullOnce/Pull -> handleEvent when message.Header != nil but message.Header.Source == nil in the unmarshaled papi message.","commonSituations":"Sender built the header without populating source; older sender version predating the Source field; hand-crafted or test messages posted to the channel.","solutions":["Upgrade or fix the sending side to include the source user in every message header","Check sender version compatibility with the receiving CrowdSec version","Validate the message format with a sample payload before publishing"],"exampleFix":"// before (sender)\nmsg := Message{Header: &Header{OperationType: op}}\n// after\nmsg := Message{Header: &Header{OperationType: op, Source: &User{ID: srcID}}}","handlingStrategy":"try-catch","validationCode":"if msg.Header != nil && msg.Header.Source == nil {\n    return errors.New(\"header missing source user\")\n}","typeGuard":"func hasSource(m *Message) bool {\n    return m != nil && m.Header != nil && m.Header.Source != nil\n}","tryCatchPattern":"if err := p.handleEvent(ctx, event); err != nil {\n    log.WithError(err).Debug(\"skipping message\")\n    continue\n}","preventionTips":["Populate Source on every header in the sender","Add a sender-side unit test asserting non-nil header and source","Check for version drift between peers after upgrades"],"tags":["papi","json","polling","message"],"backgroundTag":"unexpected-api-response-shape","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"}