alibaba/arthas · error · IllegalArgumentException

cursor 解析失败: ${e.getMessage()}

Error message

cursor 解析失败: ${e.getMessage()}

What it means

Thrown by decodeCursor() in the ViewFile MCP tool as the outer catch wrapping any inner IllegalArgumentException (the missing path/missing offset/negative offset cases, errors 95-97). It can also surface for a cursor that fails base64url decoding or JSON parsing, since the inner operations can throw. The message appends the specific inner reason.

Source

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

            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);

        List<Path> roots = new ArrayList<>();
        if (config != null && !config.trim().isEmpty()) {
            String[] parts = config.split(",");

View on GitHub (pinned to 21cf2e9ba5)

Solutions

  1. Discard the bad cursor and call viewfile with an explicit `path` (+ offset) to start fresh, then use the newly returned cursor.
  2. Ensure the cursor is the exact base64url string returned by a prior viewfile response, unmodified.
  3. If you must build a cursor, encode JSON {"v":1,"path":<non-empty string>,"offset":<non-negative number>} with URL-safe base64, no padding.

Example fix

// before
viewfile(cursor="not-a-valid-cursor")
// after
viewfile(path="/var/log/app.log", offset=0)  // get a fresh cursor, then reuse it
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate a cursor before sending it: decode + check shape
static boolean isValidCursor(String cursor) {
    try {
        String json = new String(Base64.getUrlDecoder().decode(cursor), StandardCharsets.UTF_8);
        Map<String,Object> m = JsonParser.fromJson(json, new TypeReference<Map<String,Object>>(){});
        return m.get("path") instanceof String && !((String)m.get("path")).trim().isEmpty()
            && m.get("offset") instanceof Number && ((Number)m.get("offset")).longValue() >= 0;
    } catch (Exception e) { return false; }
}

Type guard

null

Try / catch

try {
    viewfile(cursor);
} catch (IllegalArgumentException e) {
    if (e.getMessage().startsWith("cursor 解析失败")) {
        // discard the bad cursor, fall back to a fresh path-based call
        viewfile(path, 0L);
    } else throw e;
}

Prevention

When it happens

Trigger: Calling viewfile with any malformed cursor: not valid base64url, not valid JSON, or valid JSON missing required fields / with a negative offset. Any IllegalArgumentException inside the try block is rethrown with prefix 'cursor 解析失败:'.

Common situations: Using a stale/corrupted/truncated cursor token; passing a non-cursor string into the cursor field; client-side encoding bug; manually edited cursor.

Related errors


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