{"record":{"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/f070c699a08b5d8393df9afd147af5c5e90bb21b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassBasedTestDescriptor.java#L382-L418","documentation":"Thrown when a TestInstanceFactory returns an object that is not null but is not assignable to the test class. The check uses getTestClass().isInstance(instance); when FQNs collide due to ClassLoader differences, identity hash codes are appended to the names so you can tell the two definitions apart.","triggerScenarios":"Factory returns an instance whose Class differs from getTestClass() - returns a subclass loaded by a different loader, returns an unrelated type, or returns a Mockito proxy class whose superclass is not the test class.","commonSituations":"Test class loaded twice by different ClassLoaders (OSGi, build tools with isolated test classpaths), factory mistakenly returns a wrapper/mock instead of the real test class, or Kotlin companion-object misuse where the factory returns the companion instead of an instance.","solutions":["Make the factory return ctx.getTestClass().getDeclaredConstructor().newInstance() (or equivalent) so the instance is literally of the test class.","Resolve ClassLoader conflicts so the test class is loaded exactly once - align the test runtime classpath and remove duplicate classpath entries.","If the factory must proxy, return a subclass that genuinely extends the test class via ByteBuddy/cglib."],"exampleFix":"// before\n@Override\npublic Object createTestInstance(TestInstanceFactoryContext ctx, ExtensionContext ec) {\n    return mock(ctx.getTestClass()); // Mockito mock is NOT a test-class instance\n}\n// after\n@Override\npublic Object createTestInstance(TestInstanceFactoryContext ctx, ExtensionContext ec) {\n    return ctx.getTestClass().getDeclaredConstructor().newInstance();\n}","handlingStrategy":"type-guard","validationCode":"Object instance = factory.createTestInstance(ctx, extensionContext);\nif (instance == null || !ctx.getTestClass().isInstance(instance)) {\n    throw new IllegalStateException(\"Factory returned wrong type: \" + (instance == null ? \"null\" : instance.getClass()));\n}","typeGuard":"Class<?> testClass = ctx.getTestClass();\n// in factory\nObject inst = buildInstance();\nif (!testClass.isInstance(inst)) {\n    throw new TestInstantiationException(\"not a \" + testClass.getName() + \": \" + inst.getClass());\n}\nreturn inst;","tryCatchPattern":null,"preventionTips":["Have your factory return ctx.getTestClass().getDeclaredConstructor().newInstance() by default.","Resolve ClassLoader mismatches so the test class is loaded once.","Avoid returning Mockito mocks or proxies whose Class differs from the test class."],"tags":["test-instance-factory","type-mismatch","classloader","instantiation"],"backgroundTag":null,"analyzedSha":"f070c699a08b5d8393df9afd147af5c5e90bb21b","analyzedAt":"2026-08-11T20:31:00.530Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}