{"record":{"id":"5ddb526cab28faeb","repo":"alibaba/arthas","slug":"offset","errorCode":null,"errorMessage":"offset 不允许为负数","messagePattern":"offset 不允许为负数","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/com/taobao/arthas/core/mcp/tool/function/basic1000/ViewFileTool.java","lineNumber":123,"sourceCode":"        private final boolean cursorUsed;\n\n        private CursorRequest(String path, long offset, boolean cursorUsed) {\n            this.path = path;\n            this.offset = offset;\n            this.cursorUsed = cursorUsed;\n        }\n    }\n\n    private CursorRequest parseCursorOrArgs(String path, String cursor, Long offset) {\n        if (cursor != null && !cursor.trim().isEmpty()) {\n            CursorValue decoded = decodeCursor(cursor.trim());\n            return new CursorRequest(decoded.path, decoded.offset, true);\n        }\n        if (path == null || path.trim().isEmpty()) {\n            throw new IllegalArgumentException(\"必须提供 path 或 cursor\");\n        }\n        if (offset != null && offset < 0) {\n            throw new IllegalArgumentException(\"offset 不允许为负数\");\n        }\n        long resolvedOffset = (offset != null) ? offset : 0L;\n        return new CursorRequest(path.trim(), resolvedOffset, false);\n    }\n\n    private static final class CursorValue {\n        private final String path;\n        private final long offset;\n\n        private CursorValue(String path, long offset) {\n            this.path = path;\n            this.offset = offset;\n        }\n    }\n\n    private CursorValue decodeCursor(String cursor) {\n        try {\n            byte[] jsonBytes = Base64.getUrlDecoder().decode(cursor);","sourceCodeStart":105,"sourceCodeEnd":141,"githubUrl":"https://github.com/alibaba/arthas/blob/21cf2e9ba52b305290be7223b980ff504bb9cb5b/core/src/main/java/com/taobao/arthas/core/mcp/tool/function/basic1000/ViewFileTool.java#L105-L141","documentation":"Thrown by parseCursorOrArgs() in the ViewFile MCP tool when an explicit offset argument is supplied that is negative. The offset is a byte position into the file and must be >= 0. (This guard is for the args path, not the cursor path.)","triggerScenarios":"Calling viewfile with path set and offset < 0, e.g. offset=-1024, without a cursor.","commonSituations":"Passing a negative seek position intending to read the tail (the tool is offset-based, not tail-based); arithmetic error computing an offset; sign mistake.","solutions":["Pass offset >= 0, or omit offset to default to 0.","To read near the end, first query file size and compute a non-negative offset."],"exampleFix":"// before\nviewfile(path=\"/var/log/app.log\", offset=-512)\n// after\nviewfile(path=\"/var/log/app.log\", offset=0)","handlingStrategy":"validation","validationCode":"if (offset != null && offset < 0) {\n    throw new IllegalArgumentException(\"offset must be >= 0\");\n}","typeGuard":"static boolean isValidOffset(Long offset) {\n    return offset == null || offset >= 0;\n}","tryCatchPattern":"null","preventionTips":["Pass offset >= 0, or omit it to default to 0.","Compute tail-read offsets from a known file size, never as a negative."],"tags":["arthas","mcp","viewfile","input-validation","offset"],"backgroundTag":null,"analyzedSha":"21cf2e9ba52b305290be7223b980ff504bb9cb5b","analyzedAt":"2026-08-14T00:57:07.243Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}