{"record":{"id":"19d4dfb9574e8299","repo":"LSPosed/LSPosed","slug":"offset-offset-is-out-of-range-for-filename","errorCode":null,"errorMessage":"Offset ${offset} is out of range for ${filename}","messagePattern":"Offset (.+?) is out of range for (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/de/robv/android/xposed/services/DirectAccessService.java","lineNumber":94,"sourceCode":"        // Check range\n        if (offset > 0 && offset >= size) {\n            throw new IllegalArgumentException(\"Offset \" + offset + \" is out of range for \" + filename);\n        } else if (offset < 0) {\n            offset = 0;\n        }","sourceCodeStart":null,"sourceCodeEnd":null,"githubUrl":"https://github.com/LSPosed/LSPosed/blob/df74d83eb03a44cc6ad268841ac2ada28d077c77/core/src/main/java/org/lsposed/lspd/services/DirectAccessService.java#L94","documentation":"DirectAccessService.readFile(filename, offset, length, previousSize, previousTime) throws IllegalArgumentException when a positive offset is greater than or equal to the current file size. The range check at line 93 exists because the subsequent FileInputStream.skip(offset) would have nothing left to read, so the API rejects the call instead of returning empty data.","triggerScenarios":"Calling readFile(path, offset, length, prevSize, prevTime) with offset >= file.length(), typically after the file shrank or was truncated between a previous stat/read and this call (previousSize/previousTime mismatch forces the full read path).","commonSituations":"Polling a log or config file that gets rotated/truncated (e.g. logcat-style rotation); caching (size, mtime) from a previous read and re-reading with an old offset after the file was recreated smaller.","solutions":["Re-stat the file (statFile) before reading and clamp offset to Math.min(offset, size - 1) or re-read from 0","If the file was rotated/truncated, reset your cached previousSize/previousTime and read the whole file","Handle offset <= 0 if you actually want the whole file — that takes the readFile shortcut with no range check"],"exampleFix":"// before\nFileResult r = service.readFile(path, cachedOffset, len, prevSize, prevTime);\n\n// after\nFileResult st = service.statFile(path);\nif (cachedOffset >= st.size) {\n    cachedOffset = 0; // file shrank or rotated, restart\n}\nFileResult r = service.readFile(path, (int) cachedOffset, len, st.size, st.mtime);","handlingStrategy":"validation","validationCode":"FileResult st = service.statFile(filename);\nif (offset > 0 && offset >= st.size) {\n    offset = 0; // file shrank/rotated — restart from beginning\n}","typeGuard":null,"tryCatchPattern":"try {\n    return service.readFile(filename, offset, length, prevSize, prevTime);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage() != null && e.getMessage().startsWith(\"Offset\")) {\n        return service.readFile(filename); // fall back to full read\n    }\n    throw e;\n}","preventionTips":["Always pair a cached offset with a fresh statFile result","Treat file shrinkage (rotation) as a signal to reset cached offset and previousSize/previousTime","Prefer offset <= 0 / length <= 0 for whole-file reads — that path skips the range checks"],"tags":["io","file-access","offset","validation","argument-error"],"backgroundTag":null,"analyzedSha":"df74d83eb03a44cc6ad268841ac2ada28d077c77","analyzedAt":"2026-08-14T10:46:48.326Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}