{"record":{"id":"3d22cb90375740c9","repo":"hashicorp/nomad","slug":"no-more-logs","errorCode":null,"errorMessage":"no more logs","messagePattern":"no more logs","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"info","filePath":"helper/raftutil/fsm.go","lineNumber":20,"sourceCode":"// SPDX-License-Identifier: BUSL-1.1\n\npackage raftutil\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n\n\t\"github.com/hashicorp/go-hclog\"\n\t\"github.com/hashicorp/go-memdb\"\n\t\"github.com/hashicorp/nomad/nomad\"\n\t\"github.com/hashicorp/nomad/nomad/state\"\n\t\"github.com/hashicorp/nomad/nomad/structs\"\n\t\"github.com/hashicorp/raft\"\n)\n\nvar ErrNoMoreLogs = fmt.Errorf(\"no more logs\")\n\ntype nomadFSM interface {\n\traft.FSM\n\tState() *state.StateStore\n\tRestore(io.ReadCloser) error\n\tRestoreWithFilter(io.ReadCloser, *nomad.FSMFilter) error\n}\n\ntype FSMHelper struct {\n\tpath string\n\n\tlogger hclog.Logger\n\n\t// nomad state\n\tstore RaftStore\n\tfsm   nomadFSM\n\tsnaps *raft.FileSnapshotStore\n","sourceCodeStart":2,"sourceCodeEnd":38,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/helper/raftutil/fsm.go#L2-L38","documentation":"ErrNoMoreLogs is a sentinel error exported from helper/raftutil indicating the FSM helper has applied every available Raft log: nextIdx has passed logLastIdx. It is not a failure — ApplyUntil and ApplyAll treat it as the normal termination signal for replaying logs.","triggerScenarios":"Calling ApplyNext on an FSMHelper whose nextIdx exceeds the store's last log index; it is also returned by ApplyUntil and ApplyAll when replay reaches the end of the log.","commonSituations":"Tooling that replays a Nomad server's Raft log offline (debugging, migration, state inspection) reaching the end of the log; testing with TestSampleInvariant where replay exhaustion is expected.","solutions":["Treat it as success: compare with errors.Is(err, raftutil.ErrNoMoreLogs) and stop the replay loop","No fix needed — this signals normal completion of log replay"],"exampleFix":"// before\nidx, term, err := f.ApplyNext()\nif err != nil { return err }\n// after\nidx, term, err := f.ApplyNext()\nif errors.Is(err, raftutil.ErrNoMoreLogs) {\n    return lastIdx, lastTerm, nil // replay complete\n} else if err != nil {\n    return err\n}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"func isNoMoreLogs(err error) bool { return errors.Is(err, raftutil.ErrNoMoreLogs) }","tryCatchPattern":"idx, term, err := f.ApplyNext()\nif errors.Is(err, raftutil.ErrNoMoreLogs) {\n    return lastIdx, lastTerm, nil // success: log exhausted\n}\nif err != nil {\n    return err\n}","preventionTips":["Always compare with errors.Is against the exported ErrNoMoreLogs sentinel, never string matching","Treat it as a success/termination signal in replay loops","Structure replay loops to break on this sentinel explicitly"],"tags":["raft","sentinel-error","go"],"backgroundTag":"sentinel-error-exhausted","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"}