{"record":{"id":"a28cbedf94303738","repo":"hibiken/asynq","slug":"cannot-encode-nil-message","errorCode":null,"errorMessage":"cannot encode nil message","messagePattern":"cannot encode nil message","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/base/base.go","lineNumber":305,"sourceCode":"\t// GroupKey holds the group key used for task aggregation.\n\t//\n\t// Empty string indicates no aggregation is used for this task.\n\tGroupKey string\n\n\t// Retention specifies the number of seconds the task should be retained after completion.\n\tRetention int64\n\n\t// CompletedAt is the time the task was processed successfully in Unix time,\n\t// the number of seconds elapsed since January 1, 1970 UTC.\n\t//\n\t// Use zero to indicate no value.\n\tCompletedAt int64\n}\n\n// EncodeMessage marshals the given task message and returns an encoded bytes.\nfunc EncodeMessage(msg *TaskMessage) ([]byte, error) {\n\tif msg == nil {\n\t\treturn nil, fmt.Errorf(\"cannot encode nil message\")\n\t}\n\treturn proto.Marshal(&pb.TaskMessage{\n\t\tType:         msg.Type,\n\t\tPayload:      msg.Payload,\n\t\tHeaders:      msg.Headers,\n\t\tId:           msg.ID,\n\t\tQueue:        msg.Queue,\n\t\tRetry:        int32(msg.Retry),\n\t\tRetried:      int32(msg.Retried),\n\t\tErrorMsg:     msg.ErrorMsg,\n\t\tLastFailedAt: msg.LastFailedAt,\n\t\tTimeout:      msg.Timeout,\n\t\tDeadline:     msg.Deadline,\n\t\tUniqueKey:    msg.UniqueKey,\n\t\tGroupKey:     msg.GroupKey,\n\t\tRetention:    msg.Retention,\n\t\tCompletedAt:  msg.CompletedAt,\n\t})","sourceCodeStart":287,"sourceCodeEnd":323,"githubUrl":"https://github.com/hibiken/asynq/blob/d135f1439bee74e989b7f9b41ecd542cc87f024a/internal/base/base.go#L287-L323","documentation":"base.EncodeMessage rejects a nil *TaskMessage before attempting protobuf marshaling, returning 'cannot encode nil message'. Encoding a nil message would otherwise panic or produce a meaningless empty payload, so the library fails with an explicit error.","triggerScenarios":"Calling base.EncodeMessage(nil) directly, or indirectly via Enqueue/BatchEnqueue paths where a nil message was constructed (e.g. building a TaskMessage from a task whose fields were never populated and a nil deref-guard path hit).","commonSituations":"Custom enqueue code assembling TaskMessage structs where a nil pointer slips into a slice used for BatchEnqueue; reflection/generic helpers returning nil on error but the caller proceeding anyway.","solutions":["Check msg != nil before calling EncodeMessage and return a descriptive error early.","Validate every element of a batch before enqueuing; skip or fail loudly on nil entries.","Fix the constructor/builder that produced the nil message instead of guarding at the encode site.","Use asynq.NewTask(...).Message() (higher-level API) so a nil message cannot be constructed accidentally."],"exampleFix":"// before\npayload, _ := base.EncodeMessage(msg)\n// after\nif msg == nil { return fmt.Errorf(\"task message not initialized\") }\npayload, err := base.EncodeMessage(msg)","handlingStrategy":"type-guard","validationCode":"if msg == nil { return nil, fmt.Errorf(\"cannot encode nil message\") }","typeGuard":"func msgReady(m *base.TaskMessage) bool { return m != nil && m.ID != \"\" && m.Type != \"\" && m.Queue != \"\" }","tryCatchPattern":null,"preventionTips":["Never append nil *TaskMessage to batches; filter first","Construct messages via asynq.NewTask so nils are impossible","Check builder functions for nil-return-on-error and handle before encoding"],"tags":["nil-value","encoding","asynq"],"backgroundTag":"null-argument","analyzedSha":"d135f1439bee74e989b7f9b41ecd542cc87f024a","analyzedAt":"2026-09-07T19:02:34.660Z","contentChangedAt":"2026-09-07T19:02:34.660Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}