karatelabs/karate · error

Invalid number: bare '-'

Error message

Invalid number: bare '-'

What it means

Karate's internal JSON tokenizer (JsonParser.parseNumber) rejects a number token that begins with '-' but has no digits after it. JSON numbers may be negative, but a lone minus sign is not a valid number literal. The parser checks the character after '-' and throws a syntax error if the input ends or a non-numeric token follows.

Solutions

  1. Inspect the JSON string at the reported position and replace the bare '-' with a valid number (e.g. 0 or the intended negative value).
  2. If the JSON is built dynamically, ensure numeric variables are never interpolated as empty/null and quote placeholders that may be absent.
  3. Validate the payload with a JSON linter/parser before passing it to Karate to get a clearer diff of the malformed spot.
  4. If the value is genuinely optional, emit 'null' instead of '-' for missing numbers.

Example fix

// before
String json = "{\"amount\": " + amount + "}"; // amount == "" -> {"amount": -}
// after
String lit = (amount == null || amount.isEmpty()) ? "null" : amount;
String json = "{\"amount\": " + lit + "}";
Defensive patterns

Strategy: validation

Validate before calling

// Java: check the payload parses strictly before use
try (var p = new java.io.PushbackReader(new java.io.StringReader(json))) { /* or */ }
// simplest guard:
boolean valid = com.jayway.jsonpath.JsonPath.parse(json) != null; // or pre-scan for bare '-':
if (json.matches(".*[^0-9\\.eE]-\\s*[,}\\]].*") || json.trim().endsWith("-")) {
    throw new IllegalArgumentException("bare '-' is not a valid JSON number");
}

Try / catch

// Java
try {
    Json json = Json.of(raw);
} catch (Exception e) {
    if (e.getMessage() != null && e.getMessage().contains("Invalid number")) {
        // sanitize placeholder tokens and retry
        raw = raw.replaceAll("-\\s*([,}\\]]|$)", "null$1");
    } else { throw e; }
}

Prevention

When it happens

Trigger: Calling the JSON parser (e.g. Json.of(...)/Json.parse on a string) with input where a value position contains '-' immediately followed by end-of-input or a delimiter, e.g. '[1, -]', '{"a": -}' or a trailing '-' after whitespace trimming.

Common situations: Hand-edited JSON config files where a negative value was never filled in; template/placeholder substitution that left '-' behind; string concatenation building JSON where a variable defaulted to empty; truncated responses ending mid-token.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12). Data as JSON: /api/errors/d17eb40c97f6d564. Report an issue: GitHub.

Appendix: source

Thrown at karate-js/src/main/java/io/karatelabs/js/JsonParser.java:261

                char h = s.charAt(pos + i);
                int d;
                if (h >= '0' && h <= '9') d = h - '0';
                else if (h >= 'a' && h <= 'f') d = 10 + (h - 'a');
                else if (h >= 'A' && h <= 'F') d = 10 + (h - 'A');
                else throw syntaxError("Invalid hex digit '" + h + "' in \\u escape");
                v = (v << 4) | d;
            }
            pos += 4;
            return (char) v;
        }

        private Object parseNumber() {
            int start = pos;
            boolean isFloat = false;
            if (s.charAt(pos) == '-') {
                pos++;
                if (pos >= len) {
                    throw syntaxError("Invalid number: bare '-'");
                }
            }
            // integer part
            char c = s.charAt(pos);
            if (c == '0') {
                pos++;
            } else if (c >= '1' && c <= '9') {
                pos++;
                while (pos < len && (s.charAt(pos) >= '0' && s.charAt(pos) <= '9')) {
                    pos++;
                }
            } else {
                throw syntaxError("Invalid number");
            }
            // fraction
            if (pos < len && s.charAt(pos) == '.') {
                isFloat = true;
                pos++;

View on GitHub (pinned to a22eb90246)