{"record":{"id":"d6a6d275d9475118","repo":"livekit/livekit","slug":"could-not-update-egress-info","errorCode":null,"errorMessage":"could not update egress info","messagePattern":"could not update egress info","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/service/redisstore.go","lineNumber":465,"sourceCode":"}\n\nfunc (s *RedisStore) UpdateEgress(_ context.Context, info *livekit.EgressInfo) error {\n\tdata, err := proto.Marshal(info)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif info.EndedAt != 0 {\n\t\tpp := s.rc.Pipeline()\n\t\tpp.HSet(s.ctx, EgressKey, info.EgressId, data)\n\t\tpp.HSet(s.ctx, EndedEgressKey, info.EgressId, egressEndedValue(info.RoomName, info.EndedAt))\n\t\t_, err = pp.Exec(s.ctx)\n\t} else {\n\t\terr = s.rc.HSet(s.ctx, EgressKey, info.EgressId, data).Err()\n\t}\n\n\tif err != nil {\n\t\treturn errors.Wrap(err, \"could not update egress info\")\n\t}\n\n\treturn nil\n}\n\n// Deletes egress info 24h after the egress has ended\nfunc (s *RedisStore) egressWorker() {\n\tticker := time.NewTicker(time.Minute * 30)\n\tdefer ticker.Stop()\n\n\tfor {\n\t\tselect {\n\t\tcase <-s.done:\n\t\t\treturn\n\t\tcase <-ticker.C:\n\t\t\terr := s.CleanEndedEgress()\n\t\t\tif err != nil {\n\t\t\t\tlogger.Errorw(\"could not clean egress info\", err)","sourceCodeStart":447,"sourceCodeEnd":483,"githubUrl":"https://github.com/livekit/livekit/blob/ee45c3f0b1a83bf4352dbccb6607ebf70b2a5de6/pkg/service/redisstore.go#L447-L483","documentation":"UpdateEgress writes updated EgressInfo back to Redis — through a pipeline (with room-set bookkeeping) in one branch, or a plain HSet otherwise; any resulting error is wrapped as 'could not update egress info'. Status updates for running egress are lost if Redis is unhealthy.","triggerScenarios":"Either pp.Exec (pipeline branch) or HSet(EgressKey, egressId, data).Err() (single-key branch) returns a Redis error: connection drop, READONLY, timeout, cluster redirect, or OOM.","commonSituations":"Status updates failing during a Redis failover; long-running egress sessions spanning Redis restarts; writing through a replica; transient network partitions.","solutions":["Confirm the Redis endpoint is a writable master (INFO replication) and fix routing if pointing at a replica.","Check Redis and livekit logs for the underlying cause (READONLY/MOVED/timeout).","Ensure egress nodes and Redis share stable connectivity; add retries with backoff around updates.","In cluster setups, use a cluster-aware client so key-slot moves are followed.","Monitor maxmemory; large EgressInfo payloads can push Redis over the limit."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"if err := s.rc.Ping(ctx).Err(); err != nil {\n    return fmt.Errorf(\"redis unavailable, egress update will fail: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if err := store.UpdateEgress(ctx, info, mutate); err != nil {\n    if strings.Contains(err.Error(), \"could not update egress info\") {\n        // retry status update; egress status converges on success\n        backoff.Retry(func() error { return store.UpdateEgress(ctx, info, mutate) }, policy)\n    }\n}","preventionTips":["Retry status updates with backoff — egress sessions outlive transient Redis issues.","Monitor Redis stability during long-running egress jobs.","Use cluster-aware clients for key-slot moves.","Alert on failed egress status writes.","Keep EgressInfo payloads compact to reduce Redis pressure."],"tags":["redis","egress","update-failure"],"backgroundTag":"redis-write-failed","analyzedSha":"ee45c3f0b1a83bf4352dbccb6607ebf70b2a5de6","analyzedAt":"2026-09-02T03:56:08.477Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}