{"record":{"id":"ece32a788caa00b6","repo":"hibiken/asynq","slug":"cannot-encode-nil-worker-info","errorCode":null,"errorMessage":"cannot encode nil worker info","messagePattern":"cannot encode nil worker info","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/base/base.go","lineNumber":443,"sourceCode":"}\n\n// WorkerInfo holds information about a running worker.\ntype WorkerInfo struct {\n\tHost     string\n\tPID      int\n\tServerID string\n\tID       string\n\tType     string\n\tPayload  []byte\n\tQueue    string\n\tStarted  time.Time\n\tDeadline time.Time\n}\n\n// EncodeWorkerInfo marshals the given WorkerInfo and returns the encoded bytes.\nfunc EncodeWorkerInfo(info *WorkerInfo) ([]byte, error) {\n\tif info == nil {\n\t\treturn nil, fmt.Errorf(\"cannot encode nil worker info\")\n\t}\n\tstartTime := timestamppb.New(info.Started)\n\tdeadline := timestamppb.New(info.Deadline)\n\n\treturn proto.Marshal(&pb.WorkerInfo{\n\t\tHost:        info.Host,\n\t\tPid:         int32(info.PID),\n\t\tServerId:    info.ServerID,\n\t\tTaskId:      info.ID,\n\t\tTaskType:    info.Type,\n\t\tTaskPayload: info.Payload,\n\t\tQueue:       info.Queue,\n\t\tStartTime:   startTime,\n\t\tDeadline:    deadline,\n\t})\n}\n\n// DecodeWorkerInfo decodes the given bytes into WorkerInfo.","sourceCodeStart":425,"sourceCodeEnd":461,"githubUrl":"https://github.com/hibiken/asynq/blob/d135f1439bee74e989b7f9b41ecd542cc87f024a/internal/base/base.go#L425-L461","documentation":"EncodeWorkerInfo marshals a *WorkerInfo (a currently-processing task's worker record) into protobuf bytes to be stored as part of server state. The library throws this when the worker info pointer is nil, since encoding an absent worker is meaningless. It prevents a nil dereference inside proto.Marshal.","triggerScenarios":"Calling base.EncodeWorkerInfo(nil) directly, or WriteServerState being handed a ServerState whose Workers slice contains a nil *WorkerInfo, or a WorkerInfo variable that was never allocated.","commonSituations":"Application code tracking in-flight tasks that appends pointers from a map lookup which returned nil; test code declaring `var w *base.WorkerInfo` without initialization; a task-processing hook that failed to build the WorkerInfo before heartbeating.","solutions":["Verify each *WorkerInfo is non-nil before adding it to ServerState.Workers or passing it to EncodeWorkerInfo.","Fix the producer that should construct WorkerInfo (Host, PID, ID, Queue, TaskMessage fields) so it never yields nil.","Filter nil entries when building the Workers slice."],"exampleFix":"// before\nworkers := make([]*base.WorkerInfo, len(active))\nfor i, t := range active {\n    workers[i] = workerMap[t.ID] // may be nil\n}\n// after\nvar workers []*base.WorkerInfo\nfor _, t := range active {\n    if w := workerMap[t.ID]; w != nil {\n        workers = append(workers, w)\n    }\n}","handlingStrategy":"type-guard","validationCode":"for _, w := range workers {\n    if w == nil {\n        return errors.New(\"nil worker info in server state\")\n    }\n}","typeGuard":"func validWorker(w *base.WorkerInfo) bool { return w != nil && w.ID != \"\" }","tryCatchPattern":"b, err := base.EncodeWorkerInfo(w)\nif err != nil {\n    log.Printf(\"skip worker %s: %v\", wID, err)\n    continue\n}","preventionTips":["Filter nil entries out of ServerState.Workers before writing.","Handle map-lookup misses (w, ok := m[id]) instead of storing nil pointers.","Keep WorkerInfo construction in one factory function that always returns non-nil or an error."],"tags":["go","nil-pointer","serialization","protobuf"],"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"}