alibaba/arthas · error · IllegalArgumentException

cursor offset 不允许为负数

Error message

cursor offset 不允许为负数

What it means

Thrown by decodeCursor() in the ViewFile MCP tool when the cursor's offset field is a Number but is negative. Even when supplied via cursor, the resume offset must be >= 0. Surfaced to the caller as 'cursor 解析失败: cursor offset 不允许为负数' (error 98).

Source

Thrown at core/src/main/java/com/taobao/arthas/core/mcp/tool/function/basic1000/ViewFileTool.java:155

    }

    private CursorValue decodeCursor(String cursor) {
        try {
            byte[] jsonBytes = Base64.getUrlDecoder().decode(cursor);
            String json = new String(jsonBytes, StandardCharsets.UTF_8);

            Map<String, Object> map = JsonParser.fromJson(json, new TypeReference<Map<String, Object>>() {});
            Object pathObj = map.get("path");
            Object offsetObj = map.get("offset");
            if (!(pathObj instanceof String) || ((String) pathObj).trim().isEmpty()) {
                throw new IllegalArgumentException("cursor 缺少 path");
            }
            if (!(offsetObj instanceof Number)) {
                throw new IllegalArgumentException("cursor 缺少 offset");
            }
            long offset = ((Number) offsetObj).longValue();
            if (offset < 0) {
                throw new IllegalArgumentException("cursor offset 不允许为负数");
            }
            return new CursorValue(((String) pathObj).trim(), offset);
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException("cursor 解析失败: " + e.getMessage(), e);
        }
    }

    private String encodeCursor(String path, long offset) {
        Map<String, Object> cursor = new LinkedHashMap<>();
        cursor.put("v", 1);
        cursor.put("path", path);
        cursor.put("offset", offset);
        String json = JsonParser.toJson(cursor);
        return Base64.getUrlEncoder().withoutPadding().encodeToString(json.getBytes(StandardCharsets.UTF_8));
    }

    private List<Path> loadAllowedRoots() {
        String config = System.getenv(ALLOWED_DIRS_ENV);

View on GitHub (pinned to 21cf2e9ba5)

Solutions

  1. Use cursor tokens produced by prior viewfile calls (their offset is always >= 0).
  2. If constructing manually, set offset to a non-negative value.

Example fix

// before
cursor = base64url({"v":1,"path":"/var/log/app.log","offset":-100})
// after
cursor = base64url({"v":1,"path":"/var/log/app.log","offset":0})
Defensive patterns

Strategy: validation

Validate before calling

long off = ((Number) offset).longValue();
if (off < 0) throw new IllegalArgumentException("offset must be >= 0");

Type guard

static boolean cursorOffsetNonNegative(Map<String,Object> m) {
    Object o = m.get("offset");
    return o instanceof Number && ((Number) o).longValue() >= 0;
}

Try / catch

null

Prevention

When it happens

Trigger: Calling viewfile with a cursor whose decoded offset is < 0, e.g. {"v":1,"path":"/x","offset":-100} encoded as base64url.

Common situations: Tampered or buggy cursor with a negative offset; arithmetic mistake when generating a cursor client-side.

Related errors


AI-assisted analysis of alibaba/arthas@21cf2e9ba5 (2026-08-14). Data as JSON: /api/errors/76f52ac8f0bf1ffd. Report an issue: GitHub.