{"id":"aae138136ccb1284","repo":"google/gson","slug":"expected-a-requestedtype-getname-but-was","errorCode":null,"errorMessage":"Expected a \" + requestedType.getName() + \" but was \" + result.getClass().getName() + \"; at path \" + in.getPreviousPath()","messagePattern":"Expected a \" \\+ requestedType\\.getName\\(\\) \\+ \" but was \" \\+ result\\.getClass\\(\\)\\.getName\\(\\) \\+ \"; at path \" \\+ in\\.getPreviousPath\\(\\)","errorType":"exception","errorClass":"JsonSyntaxException","httpStatus":null,"severity":"error","filePath":"gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java","lineNumber":1081,"sourceCode":"      @SuppressWarnings(\"unchecked\")\n      @Override\n      public <T2> TypeAdapter<T2> create(Gson gson, TypeToken<T2> typeToken) {\n        Class<? super T2> requestedType = typeToken.getRawType();\n        if (!clazz.isAssignableFrom(requestedType)) {\n          return null;\n        }\n        return (TypeAdapter<T2>)\n            new TypeAdapter<T1>() {\n              @Override\n              public void write(JsonWriter out, T1 value) throws IOException {\n                typeAdapter.write(out, value);\n              }\n\n              @Override\n              public T1 read(JsonReader in) throws IOException {\n                T1 result = typeAdapter.read(in);\n                if (result != null && !requestedType.isInstance(result)) {\n                  throw new JsonSyntaxException(\n                      \"Expected a \"\n                          + requestedType.getName()\n                          + \" but was \"\n                          + result.getClass().getName()\n                          + \"; at path \"\n                          + in.getPreviousPath());\n                }\n                return result;\n              }\n            };\n      }\n\n      @Override\n      public String toString() {\n        return \"Factory[typeHierarchy=\" + clazz.getName() + \",adapter=\" + typeAdapter + \"]\";\n      }\n    };\n  }","sourceCodeStart":1063,"sourceCodeEnd":1099,"githubUrl":"https://github.com/google/gson/blob/8b8628c65699bc4421696183c62ae0c1b9b281dc/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java#L1063-L1099","documentation":"Gson's newTypeHierarchyFactory wraps an adapter so that, after reading, it verifies the result is an instance of the requested type. If the delegate produces a different concrete type, Gson throws JsonSyntaxException 'Expected a <X> but was <Y>'. This catches mismatches in type-hierarchy adapters (e.g. Number, InetAddress, Collection).","triggerScenarios":"Deserializing a type that uses a hierarchy factory (such as Collection, Number, InetAddress subclasses) where the underlying adapter returns a concrete type that is not assignable to the declared target type, e.g. asking for Set but the factory only ever produces List.","commonSituations":"Registering a custom adapter for a supertype that returns an incompatible subtype, declaring an interface/abstract type whose only available implementation is not assignable, or a JSON shape that makes the default adapter choose a different concrete class.","solutions":["Ensure the registered TypeAdapter returns an instance assignable to the requested type.","Register an InstanceCreator or factory for the specific concrete subtype you expect.","Use a concrete target type (e.g. ArrayList instead of Collection) when deserializing.","If you wrote a custom hierarchy adapter, add a runtime check and construct the correct concrete type."],"exampleFix":"// before: adapter for Number returns Double even when Long is requested\nGson g = new GsonBuilder().registerTypeHierarchyAdapter(Number.class, (JsonSerializer<Number>)(s, t, c) -> new JsonPrimitive(s.doubleValue())).create();\n\n// after: register a factory that honors the requested type\nGson g = new GsonBuilder().registerTypeAdapterFactory(new TypeAdapterFactory() {\n    @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {\n        if (!Number.class.isAssignableFrom(type.getRawType())) return null;\n        return (TypeAdapter<T>) new TypeAdapter<Number>() {\n            @Override public Number read(JsonReader in) throws IOException { return in.nextLong(); }\n            @Override public void write(JsonWriter out, Number v) throws IOException { out.value(v); }\n        };\n    }\n}).create();","handlingStrategy":"try-catch","validationCode":"boolean adapterReturnsAssignable(TypeAdapterFactory f, Gson g, TypeToken<?> requested) {\n  // smoke-test: build adapter and parse a sample; verify instance type\n  return true; // real validation is integration testing the factory\n}","typeGuard":"static boolean isAssignableTo(Class<?> requested, Object result) {\n  return result == null || requested.isInstance(result);\n}","tryCatchPattern":"try {\n  T result = gson.fromJson(json, type);\n} catch (JsonSyntaxException e) {\n  if (e.getMessage().contains(\"Expected a\")) { /* register correct factory or use concrete type */ }\n  else throw e;\n}","preventionTips":["Use concrete target types (ArrayList, HashSet) instead of interfaces where possible.","Unit-test custom hierarchy factories with all expected subtypes.","Ensure custom adapters return instances assignable to the requested raw type."],"tags":["gson","deserialization","type-hierarchy","type-mismatch","json"],"analyzedSha":"8b8628c65699bc4421696183c62ae0c1b9b281dc","analyzedAt":"2026-08-04T19:12:22.202Z","schemaVersion":2}