{"id":"b574cbb693b2bb7f","repo":"google/gson","slug":"gson-cannot-serialize-or-deserialize-type","errorCode":null,"errorMessage":"GSON cannot serialize or deserialize {type}","messagePattern":"GSON cannot serialize or deserialize (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"gson/src/main/java/com/google/gson/Gson.java","lineNumber":498,"sourceCode":"    boolean skipPastFound = false;\n    for (TypeAdapterFactory factory : factories) {\n      if (!skipPastFound) {\n        @SuppressWarnings(\"ReferenceEquality\")\n        boolean isSkipPast = factory == skipPast;\n        if (isSkipPast) {\n          skipPastFound = true;\n        }\n        continue;\n      }\n\n      TypeAdapter<T> candidate = factory.create(this, type);\n      if (candidate != null) {\n        return candidate;\n      }\n    }\n\n    if (skipPastFound) {\n      throw new IllegalArgumentException(\"GSON cannot serialize or deserialize \" + type);\n    } else {\n      // Probably a factory from @JsonAdapter on a field\n      return getAdapter(type);\n    }\n  }\n\n  /**\n   * This method serializes the specified object into its equivalent representation as a tree of\n   * {@link JsonElement}s. This method should be used when the specified object is not a generic\n   * type. This method uses {@link Class#getClass()} to get the type for the specified object, but\n   * the {@code getClass()} loses the generic type information because of the Type Erasure feature\n   * of Java. Note that this method works fine if any of the object fields are of generic type, just\n   * the object itself should not be of a generic type. If the object is of generic type, use {@link\n   * #toJsonTree(Object, Type)} instead.\n   *\n   * @param src the object for which JSON representation is to be created\n   * @return JSON representation of {@code src}.\n   * @since 1.4","sourceCodeStart":480,"sourceCodeEnd":516,"githubUrl":"https://github.com/google/gson/blob/8b8628c65699bc4421696183c62ae0c1b9b281dc/gson/src/main/java/com/google/gson/Gson.java#L480-L516","documentation":"Thrown by Gson.getDelegateAdapter(skipPast, type) when the skipPast factory WAS found among the registered factories, but no factory AFTER it returns a non-null adapter for the type. getDelegateAdapter is the standard way for a custom TypeAdapterFactory to obtain the 'default' adapter for a type (skipping itself); if there is no default, Gson gives up with this IllegalArgumentException.","triggerScenarios":"A custom factory calls gson.getDelegateAdapter(this, type) but the type is one Gson cannot handle reflectively (no constructor, filtered, JDK-inaccessible), and no other factory covers it; ordering mistake where the custom factory is registered last so there are no factories after it to delegate to; delegating to a type that should have had its own adapter registered.","commonSituations":"Custom wrapper factories (logging, stats, caching) that delegate to the default adapter; the wrapped type lacks a default binding; JPMS reflection blocks; the user forgot to registerTypeAdapter for a type that only the custom factory would have routed to; factory registration order placing the delegating factory at the end.","solutions":["Register a concrete TypeAdapter for the type so the delegate search succeeds (the custom factory will then delegate to it).","Ensure the custom factory is NOT the last registered factory; there must be a factory after it (Gson's built-ins usually satisfy this, unless they cannot handle the type).","If reflection is the cause, fix accessibility (InstanceCreator, add-opens) as in error 13.","Handle the null/exception path in your factory and provide a fallback adapter rather than calling getDelegateAdapter unconditionally."],"exampleFix":"// before: custom factory delegates but no default exists for the type\nclass MyFactory implements TypeAdapterFactory {\n  public <T> TypeAdapter<T> create(Gson g, TypeToken<T> t) {\n    TypeAdapter<T> d = p.getDelegateAdapter(this, t); // throws if no factory after this handles t\n    return d;\n  }\n}\n\n// after: register a real adapter so delegation succeeds, and guard\nclass MyFactory implements TypeAdapterFactory {\n  public <T> TypeAdapter<T> create(Gson p, TypeToken<T> t) {\n    TypeAdapter<T> d = p.getDelegateAdapter(this, t);\n    return d == null ? null : new MyWrapper<>(d);\n  }\n}\nGson gson = new GsonBuilder()\n    .registerTypeAdapter(NoDefaultCtor.class, new NoDefaultCtorIC())\n    .registerTypeAdapterFactory(new MyFactory())\n    .create();","handlingStrategy":"try-catch","validationCode":"// In a delegating factory, check before calling getDelegateAdapter\nTypeAdapter<?> probe = null;\ntry {\n  probe = gson.getDelegateAdapter(this, type);\n} catch (IllegalArgumentException e) {\n  // no default; return null so other factories can run\n  return null;\n}","typeGuard":null,"tryCatchPattern":"try {\n  TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);\n  return new MyWrapper<>(delegate);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().contains(\"cannot serialize or deserialize\")) {\n    return null; // let other factories handle it, or register a concrete adapter\n  } else throw e;\n}","preventionTips":["Never place a delegating factory last; ensure factories follow it (Gson's built-ins usually do).","Register concrete adapters for types that lack a reflective default.","Guard getDelegateAdapter with try/catch and return null to fall through gracefully.","Fix accessibility (InstanceCreator, add-opens) for types Gson cannot reflect."],"tags":["gson-core","type-adapter","delegate","factory-ordering","configuration"],"analyzedSha":"8b8628c65699bc4421696183c62ae0c1b9b281dc","analyzedAt":"2026-08-04T19:12:22.202Z","schemaVersion":2}