{"id":"787d6ec285f255f4","repo":"junit-team/junit5","slug":"testinstancefactory-s-failed-to-return-an-insta","errorCode":null,"errorMessage":"TestInstanceFactory [%s] failed to return an instance of [%s] and instead returned an instance of [%s].","messagePattern":"TestInstanceFactory \\[(.+?)\\] failed to return an instance of \\[(.+?)\\] and instead returned an instance of \\[(.+?)\\]\\.","errorType":"exception","errorClass":"TestInstantiationException","httpStatus":null,"severity":"error","filePath":"junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassBasedTestDescriptor.java","lineNumber":400,"sourceCode":"\t\t\tthrow new TestInstantiationException(message, throwable);\n\t\t}\n\n\t\tif (!getTestClass().isInstance(instance)) {\n\t\t\tString testClassName = getTestClass().getName();\n\t\t\tClass<?> instanceClass = (instance == null ? null : instance.getClass());\n\t\t\tString instanceClassName = (instanceClass == null ? \"null\" : instanceClass.getName());\n\n\t\t\t// If the test instance was loaded via a different ClassLoader, append\n\t\t\t// the identity hash codes to the type names to help users disambiguate\n\t\t\t// between otherwise identical \"fully qualified class names\".\n\t\t\tif (testClassName.equals(instanceClassName)) {\n\t\t\t\ttestClassName += \"@\" + Integer.toHexString(System.identityHashCode(getTestClass()));\n\t\t\t\tinstanceClassName += \"@\" + Integer.toHexString(System.identityHashCode(instanceClass));\n\t\t\t}\n\t\t\tString message = \"TestInstanceFactory [%s] failed to return an instance of [%s] and instead returned an instance of [%s].\".formatted(\n\t\t\t\ttestInstanceFactory.getClass().getName(), testClassName, instanceClassName);\n\n\t\t\tthrow new TestInstantiationException(message);\n\t\t}\n\n\t\treturn instance;\n\t}\n\n\tprivate Object invokeTestClassConstructor(@Nullable Object outerInstance, ExtensionRegistry registry,\n\t\t\tExtensionContextSupplier extensionContext) {\n\n\t\tConstructor<?> constructor = ReflectionUtils.getDeclaredConstructor(getTestClass());\n\t\treturn executableInvoker.invoke(constructor, outerInstance, extensionContext, registry,\n\t\t\tInvocationInterceptor::interceptTestClassConstructor);\n\t}\n\n\tprivate void invokeTestInstancePreConstructCallbacks(TestInstanceFactoryContext factoryContext,\n\t\t\tExtensionRegistry registry, ExtensionContextSupplier context) {\n\t\tregistry.stream(TestInstancePreConstructCallback.class).forEach(extension -> executeAndMaskThrowable(\n\t\t\t() -> extension.preConstructTestInstance(factoryContext, context.get(extension))));\n\t}","sourceCodeStart":382,"sourceCodeEnd":418,"githubUrl":"https://github.com/junit-team/junit5/blob/956246301e03d757539f7b76dd5a91f298637563/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassBasedTestDescriptor.java#L382-L418","documentation":"Thrown by ClassBasedTestDescriptor.invokeTestInstanceFactory() when the factory returns an object that is not an instance of the test class (getTestClass().isInstance(instance) is false). When the returned class name equals the test class name (same FQCN loaded by different ClassLoaders), identity-hash codes are appended to help disambiguate classloader collisions.","triggerScenarios":"A TestInstanceFactory returns null, returns an instance of a different class, or returns an instance of the right class name loaded by a different ClassLoader than the one JUnit used to discover the test.","commonSituations":"A mock/proxy factory returning a subclass proxy that is not assignable; OSGi or custom ClassLoader setups where the test class is loaded twice; a factory that returns a shared singleton of a sibling class by mistake; returning a Mockito mock of the class when mocking final classes is disabled (mock is a different generated class).","solutions":["Make the factory return an instance created from ctx.getTestClass() directly (e.g. getTestClass().getDeclaredConstructor().newInstance()).","If using a proxy/mock, ensure the proxy class extends or implements the test class and is loaded by a ClassLoader consistent with the test.","For ClassLoader collisions, unify the loader so the test class is loaded once; the @identityHashCodes in the message diagnose this case.","Return a non-null value — null is reported as the 'returned an instance of [null]' variant of this same error."],"exampleFix":"// before\npublic Object createTestInstance(TestInstanceFactoryContext ctx, ExtensionContext ext) {\n    return SomeOtherClass.INSTANCE; // wrong type\n}\n// after\npublic Object createTestInstance(TestInstanceFactoryContext ctx, ExtensionContext ext) {\n    Class<?> c = ctx.getTestClass();\n    try { return c.getDeclaredConstructor().newInstance(); }\n    catch (Exception e) { throw new TestInstantiationException(\"fail\", e); }\n}","handlingStrategy":"validation","validationCode":"// In the factory, validate before returning\nObject instance = buildInstance(ctx.getTestClass());\nif (instance == null || !ctx.getTestClass().isInstance(instance)) {\n    throw new TestInstantiationException(\"Factory returned wrong type: \" + (instance == null ? \"null\" : instance.getClass()));\n}\nreturn instance;","typeGuard":"static boolean factoryReturnsCorrectType(TestInstanceFactory f, Class<?> testClass, ExtensionContext ctx) {\n    Object inst = f.createTestInstance(new DefaultTestInstanceFactoryContext(testClass, null), ctx);\n    return inst != null && testClass.isInstance(inst);\n}","tryCatchPattern":null,"preventionTips":["Always instantiate from ctx.getTestClass() rather than a cached Class reference.","Never return null from a TestInstanceFactory.","For proxy/mock factories, verify the proxy class is loaded by a ClassLoader consistent with the test."],"tags":["junit-jupiter","extension","test-instance-factory","type-mismatch","classloader"],"analyzedSha":"956246301e03d757539f7b76dd5a91f298637563","analyzedAt":"2026-08-04T19:25:17.049Z","schemaVersion":2}