apache/skywalking · warning · IllegalArgumentException
invalid_limits
invalid_limits
Error message
Request body is not valid JSON: {re.getMessage()}. Send an empty body for defaults, or a valid JSON object with optional `recordCap`, `retentionMillis`, `granularity` fields. What it means
DSLDebuggingRestHandler.parseLimits() accepts either an empty body (defaults) or a JSON object with optional recordCap, retentionMillis, granularity fields when creating a debugging session. Gson parsing/conversion of the body throws a RuntimeException (JsonSyntaxException or IllegalStateException from getAsJsonObject) which is converted into this IllegalArgumentException, surfaced to the REST caller as an invalid_limits error.
Source
Thrown at oap-server/server-admin/dsl-debugging/src/main/java/org/apache/skywalking/oap/server/admin/dsl/debugging/rest/DSLDebuggingRestHandler.java:449
}
/**
* Parses the optional JSON body. Throws {@link IllegalArgumentException}
* with a user-facing message on malformed JSON or out-of-range limits,
* which the caller maps to {@code 400 invalid_limits}. An empty body
* stays mapped to {@link SessionLimits#DEFAULT} so a plain
* {@code POST /dsl-debugging/session?...} without a body just works.
*/
private SessionLimits parseLimits(final HttpData body) {
if (body == null || body.length() == 0) {
return SessionLimits.DEFAULT;
}
final JsonObject root;
try {
root = JsonParser.parseString(
new String(body.array(), StandardCharsets.UTF_8)).getAsJsonObject();
} catch (final RuntimeException re) {
throw new IllegalArgumentException(
"Request body is not valid JSON: " + re.getMessage()
+ ". Send an empty body for defaults, or a valid JSON object "
+ "with optional `recordCap`, `retentionMillis`, `granularity` "
+ "fields.");
}
final int recordCap = root.has("recordCap")
? root.get("recordCap").getAsInt() : SessionLimits.DEFAULT.getRecordCap();
final long retention = root.has("retentionMillis")
? root.get("retentionMillis").getAsLong()
: SessionLimits.DEFAULT.getRetentionMillis();
final Granularity granularity = root.has("granularity")
? Granularity.ofWireName(root.get("granularity").getAsString())
: SessionLimits.DEFAULT.getGranularity();
// Let SessionLimits validate the bounds — caller surfaces 400 invalid_limits.
return new SessionLimits(recordCap, retention, granularity);
}
private static JsonObject ruleKeyToJson(final RuleKey key) {View on GitHub (pinned to 102af09b4a)
Solutions
- Send no body at all to accept defaults, or a well-formed JSON object: {"recordCap": 100, "retentionMillis": 300000, "granularity": "..."}
- Validate the payload with a JSON linter or jq before sending; pass it via a file: curl --data-binary @limits.json
- Ensure the client sends raw JSON (Content-Type: application/json) and not form-encoding
Example fix
# before
curl -X POST 'http://oap:8092/dsl-debugging/session?...' -d 'recordCap=100'
# after
curl -X POST 'http://oap:8092/dsl-debugging/session?...' \
-H 'Content-Type: application/json' \
-d '{"recordCap":100,"retentionMillis":300000}' Defensive patterns
Strategy: validation
Validate before calling
// Client-side: build the body with a JSON library, never string concat
ObjectNode n = JsonNodeFactory.instance.objectNode();
if (recordCap > 0) n.put("recordCap", recordCap);
if (retentionMillis > 0) n.put("retentionMillis", retentionMillis);
String body = n.isEmpty() ? "" : n.toString(); Type guard
function isLimitsBody(v: unknown): v is { recordCap?: number; retentionMillis?: number; granularity?: string } {
return v === undefined || (typeof v === 'object' && v !== null && !Array.isArray(v));
} Try / catch
REST clients should treat the 4xx invalid_limits response as terminal client error: surface the message (it embeds the Gson parse failure and the accepted fields) and do not retry with the same body.
Prevention
- Send no body for defaults instead of an empty object
- Use a JSON serializer (jq, jackson, gson) to construct the payload; never hand-concatenate JSON
When it happens
Trigger: POST /dsl-debugging/session with a body that is not valid JSON (truncated JSON, stray quotes, form-encoded payload), or valid JSON that is not an object (array, bare string/number); sending Content-Type JSON with an empty-but-present body containing whitespace also fails parsing.
Common situations: Calling the debugging REST API with curl and misquoted payloads; proxies or clients that mangle the body; automated scripts generating JSON via string concatenation with unescaped characters; sending a JSON array of limit objects instead of one object.
Related errors
- invalid_limits
- Failed to load GenAI configuration file.
- Output type {outputTypeName} has no setter {setterName}() fo
- {funcName}() requires exactly 1 argument, got {argCount}
- Cannot resolve method {simpleName}.{methodName}() in def var
AI-assisted analysis of apache/skywalking@102af09b4a (2026-08-14).
Data as JSON: /api/errors/4ad9720be061d2a6.
Report an issue: GitHub.