{"record":{"id":"e381ead56da657ab","repo":"hashicorp/nomad","slug":"requested-index-not-in-buffer","errorCode":null,"errorMessage":"requested index not in buffer","messagePattern":"requested index not in buffer","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/stream/event_broker.go","lineNumber":123,"sourceCode":"// the requested index if it is no longer in the buffer. If StartExactlyAtIndex is\n// set and the index is no longer in the buffer or not yet in the buffer an error\n// will be returned.\n//\n// When a caller is finished with the subscription it must call Subscription.Unsubscribe\n// to free ACL tracking resources.\nfunc (e *EventBroker) Subscribe(req *SubscribeRequest) (*Subscription, error) {\n\te.mu.Lock()\n\tdefer e.mu.Unlock()\n\n\tvar head *bufferItem\n\tvar offset int\n\tif req.Index != 0 {\n\t\thead, offset = e.eventBuf.StartAtClosest(req.Index)\n\t} else {\n\t\thead = e.eventBuf.Head()\n\t}\n\tif offset > 0 && req.StartExactlyAtIndex {\n\t\treturn nil, fmt.Errorf(\"requested index not in buffer\")\n\t} else if offset > 0 {\n\t\tmetrics.SetGauge([]string{\"nomad\", \"event_broker\", \"subscription\", \"request_offset\"}, float32(offset))\n\t\te.logger.Debug(\"requested index no longer in buffer\", \"requsted\", int(req.Index), \"closest\", int(head.Events.Index))\n\t}\n\n\t// Empty head so that calling Next on sub\n\tstart := newBufferItem(&structs.Events{Index: req.Index})\n\tstart.link.next.Store(head)\n\tclose(start.link.nextCh)\n\n\tif req.Authenticate == nil {\n\t\treq.Authenticate = func() error {\n\t\t\treturn nil\n\t\t}\n\t} else if err := req.Authenticate(); err != nil {\n\t\treturn nil, err\n\t}\n","sourceCodeStart":105,"sourceCodeEnd":141,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/stream/event_broker.go#L105-L141","documentation":"The event broker's Subscribe honors req.Index when the caller wants to resume from a specific Raft index. StartAtClosest returns the closest buffered head and an offset; if offset > 0 the requested index has already been discarded from the ring buffer, and when the caller demanded StartExactlyAtIndex the subscription cannot be established, so this exact error is returned.","triggerScenarios":"Creating a subscription (e.g. job plan/event stream RPC with Index > 0 and StartExactlyAtIndex=true) where the requested index is older than the oldest event still held by the broker's event buffer (buffer rollover).","commonSituations":"Slow or disconnected consumer reconnecting after long downtime (e.g. ACL-authenticated event stream UI resume); very chatty topics (deployment/evaluation events) flushing the small default buffer quickly; network partitions causing stale-index resumes.","solutions":["Reconnect without StartExactlyAtIndex (or with Index=0) to subscribe from the current head and re-sync.","Treat this as 'state lost' and re-fetch the authoritative resource list (job/deployments) after resubscribing.","Reduce reconnect latency / keep the stream alive so the requested index stays within the buffer window.","Server-side: increase event buffer size or shorten the stale-index window exposed to clients."],"exampleFix":"// before\nsub, err := broker.Subscribe(&stream.SubscribeRequest{Index: lastSeen, StartExactlyAtIndex: true})\n// after\nsub, err := broker.Subscribe(&stream.SubscribeRequest{Index: lastSeen, StartExactlyAtIndex: true})\nif err != nil && err.Error() == \"requested index not in buffer\" {\n  syncFullState()\n  sub, err = broker.Subscribe(&stream.SubscribeRequest{}) // resume from head\n}","handlingStrategy":"fallback","validationCode":"// Only request an exact index if it is recent enough to plausibly be buffered\nif lastSeen > 0 && time.Since(lastSeenTime) > bufferWindow {\n  req.Index = 0 // resume from head and re-sync state instead\n}","typeGuard":"func isIndexNotInBuffer(err error) bool { return err != nil && err.Error() == \"requested index not in buffer\" }","tryCatchPattern":"sub, err := broker.Subscribe(req)\nif isIndexNotInBuffer(err) {\n  syncFullState() // rebuild from authoritative API\n  sub, err = broker.Subscribe(&stream.SubscribeRequest{})\n}","preventionTips":["Bound the staleness of indexes you try to resume from.","Keep event stream connections alive (heartbeats) to avoid long reconnect gaps.","Always implement a full-state resync path for event consumers."],"tags":["nomad","event-stream","buffering","streaming"],"backgroundTag":"event-buffer-lag","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}