{"record":{"id":"52b84bd79fc08eab","repo":"hashicorp/nomad","slug":"unable-to-determine-remaining-read-limit","errorCode":null,"errorMessage":"unable to determine remaining read limit","messagePattern":"unable to determine remaining read limit","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/fs_endpoint.go","lineNumber":770,"sourceCode":"\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\t// Get a new reader at offset zero\n\t\t\t\toffset = 0\n\t\t\t\tvar err error\n\t\t\t\tfile, err = fs.ReadAt(path, offset)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tdefer file.Close()\n\n\t\t\t\tif limit <= 0 {\n\t\t\t\t\tfileReader = file\n\t\t\t\t} else {\n\t\t\t\t\t// Get the current limit\n\t\t\t\t\tlr, ok := fileReader.(*io.LimitedReader)\n\t\t\t\t\tif !ok {\n\t\t\t\t\t\treturn fmt.Errorf(\"unable to determine remaining read limit\")\n\t\t\t\t\t}\n\n\t\t\t\t\tfileReader = io.LimitReader(file, lr.N)\n\t\t\t\t}\n\n\t\t\t\t// Store the last event\n\t\t\t\tlastEvent = truncateEvent\n\t\t\t\tcontinue OUTER\n\t\t\tcase <-framer.ExitCh():\n\t\t\t\treturn nil\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn nil\n\t\t\tcase _, ok := <-eofCancelCh:\n\t\t\t\tif !ok {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\n\t\t\t\tif err != nil {","sourceCodeStart":752,"sourceCodeEnd":788,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/fs_endpoint.go#L752-L788","documentation":"In streamFile, after the log file rotates, the reader is re-wrapped to preserve the caller's byte limit. The code expects fileReader to be an *io.LimitedReader; if the type assertion fails, the remaining read limit cannot be recovered, so it returns this internal error.","triggerScenarios":"Reading logs with a finite offset/limit where the internal fileReader type is not an *io.LimitedReader at the time of a rotation — an internal invariant violation of the client's log streaming implementation, typically triggered by concurrent or unusual request shapes (plain stream with limit while rotating).","commonSituations":"Custom API consumers hitting the fs logs endpoint with odd Origin/offset/limit combinations across a rotation; rarely seen through the official Nomad API client. Mostly a client-internal bug indicator.","solutions":["Retry the request; if reproducible, file a bug with Nomad including the request parameters (origin, offset, limit) and follow flag.","Avoid unusual offset/limit combinations when following logs; use offset=0 origin=start with follow, or plain non-follow reads.","Upgrade Nomad to a version where the streaming reader wrapping was fixed.","Work around by reading logs in bounded chunks via separate non-follow requests instead of one limited follow."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":"func isReadLimitErr(err error) bool {\n    return strings.Contains(err.Error(), \"unable to determine remaining read limit\")\n}","tryCatchPattern":"if err := fetchLimitedLogs(); err != nil {\n    if isReadLimitErr(err) {\n        return fetchLogsWithPlainFollow() // drop exotic offset/limit combo\n    }\n    return err\n}","preventionTips":["Use standard parameter shapes: origin=start offset=0 follow, or simple non-follow reads.","Read in bounded chunks with separate requests rather than one limited follow across rotations.","Report reproducible occurrences as a Nomad client bug with request parameters."],"tags":["nomad","client","logs","streaming","internal"],"backgroundTag":"reader-type-assertion-failed","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"}