google/gson · error · UnsupportedOperationException

Primitive is neither a number nor a string

Error message

Primitive is neither a number nor a string

What it means

Thrown by JsonPrimitive.getAsNumber() (JsonPrimitive.java:145) as UnsupportedOperationException when the wrapped value is neither a Number nor a String. The only remaining value type a JsonPrimitive can hold is a Boolean; getAsNumber can lazily convert a String but cannot convert a Boolean, so it throws. Note: the other numeric accessors (getAsInt/getAsDouble) route through getAsString and would instead throw NumberFormatException on a boolean — this exact message is unique to getAsNumber().

Solutions

  1. Guard with primitive.isNumber() (or isString()) before calling getAsNumber()
  2. Check isBoolean() first and read it with getAsBoolean() instead
  3. Fix the schema expectation — booleans are not numbers
  4. Use a typed POJO so Gson applies the correct field type

Example fix

// before
Number n = primitive.getAsNumber(); // throws if primitive is Boolean
// after
Number n;
if (primitive.isNumber()) n = primitive.getAsNumber();
else if (primitive.isString()) n = primitive.getAsNumber(); // lazy parse
else throw new IllegalArgumentException("not numeric: " + primitive);
Defensive patterns

Strategy: type-guard

Validate before calling

JsonPrimitive p = ...;
boolean numeric = p.isNumber() || p.isString(); // getAsNumber() only safe in these cases

Type guard

static Number asNumberIfNumeric(JsonPrimitive p) {
    if (p.isNumber() || p.isString()) return p.getAsNumber();
    return null; // boolean primitive -> not numeric
}

Try / catch

try {
    Number n = primitive.getAsNumber();
} catch (UnsupportedOperationException ex) {
    // "Primitive is neither a number nor a string" -> value is Boolean
}

Prevention

When it happens

Trigger: new JsonPrimitive(true).getAsNumber(); or generic code that calls getAsNumber() on every JsonPrimitive without checking isNumber()/isBoolean(). Also a JSON boolean field read through getAsNumber().

Common situations: Generic/genericized tree-walk code that assumes all primitives are numeric; schema mismatch where a boolean field is read as a number; mixing boolean and numeric values in the same field.

Related errors


AI-assisted analysis of google/gson@310ac341f2 (2026-08-10). Data as JSON: /api/errors/3991664f5b6f2e49. Report an issue: GitHub.

Appendix: source

Thrown at gson/src/main/java/com/google/gson/JsonPrimitive.java:145

  public boolean isNumber() {
    return value instanceof Number;
  }

  /**
   * Convenience method to get this element as a {@link Number}. If this primitive {@linkplain
   * #isString() is a string}, a lazily parsed {@code Number} is constructed which parses the string
   * when any of its methods are called (which can lead to a {@link NumberFormatException}).
   *
   * @throws UnsupportedOperationException if this primitive is neither a number nor a string.
   */
  @Override
  public Number getAsNumber() {
    if (value instanceof Number) {
      return (Number) value;
    } else if (value instanceof String) {
      return new LazilyParsedNumber((String) value);
    }
    throw new UnsupportedOperationException("Primitive is neither a number nor a string");
  }

  /**
   * Check whether this primitive contains a String value.
   *
   * @return true if this primitive contains a String value, false otherwise.
   */
  public boolean isString() {
    return value instanceof String;
  }

  // Don't add Javadoc, inherit it from super implementation; no exceptions are thrown here
  @Override
  public String getAsString() {
    if (value instanceof String) {
      return (String) value;
    } else if (isNumber()) {
      return getAsNumber().toString();

View on GitHub (pinned to 310ac341f2)