{"record":{"id":"dba4ee57e41ff70c","repo":"testcontainers/testcontainers-java","slug":"configured-image-substitutor-could-not-be-loaded","errorCode":null,"errorMessage":"Configured Image Substitutor could not be loaded: ${configuredClassName}","messagePattern":"Configured Image Substitutor could not be loaded: (.+?)","errorType":"exception","errorClass":"java.lang.IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/testcontainers/utility/ImageNameSubstitutor.java","lineNumber":68,"sourceCode":"                    );\n            } else {\n                instance = wrapWithLogging(defaultImplementation);\n            }\n\n            log.info(\"Image name substitution will be performed by: {}\", instance.getDescription());\n        }\n\n        return instance;\n    }\n\n    private static ImageNameSubstitutor getImageNameSubstitutor(ClassLoader classLoader) {\n        final String configuredClassName = TestcontainersConfiguration.getInstance().getImageSubstitutorClassName();\n\n        if (configuredClassName != null) {\n            try {\n                return (ImageNameSubstitutor) classLoader.loadClass(configuredClassName).getConstructor().newInstance();\n            } catch (Exception e) {\n                throw new IllegalArgumentException(\n                    \"Configured Image Substitutor could not be loaded: \" + configuredClassName,\n                    e\n                );\n            }\n        }\n\n        return StreamSupport\n            .stream(ServiceLoader.load(ImageNameSubstitutor.class, classLoader).spliterator(), false)\n            .findFirst()\n            .orElse(null);\n    }\n\n    public static ImageNameSubstitutor noop() {\n        return new NoopImageNameSubstitutor();\n    }\n\n    private static ImageNameSubstitutor wrapWithLogging(final ImageNameSubstitutor wrappedInstance) {\n        return new LogWrappedImageNameSubstitutor(wrappedInstance);","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/testcontainers/testcontainers-java/blob/8e549514e3f01c57d70546fbb8599d138f3903e5/core/src/main/java/org/testcontainers/utility/ImageNameSubstitutor.java#L50-L86","documentation":"ImageNameSubstitutor.getImageNameSubstitutor loads a custom substitutor class named by testcontainers.image.name.substitutor in ~/.testcontainers.properties. If the class cannot be loaded, instantiated via a no-arg constructor, or cast to ImageNameSubstitutor, it throws IllegalArgumentException including the configured class name. This is a config/classpath problem surfaced at first image-name resolution.","triggerScenarios":"Setting testcontainers.image.name.substitutor=fully.qualified.ClassName where the class is not on the test classpath, lacks a public no-arg constructor, fails in its constructor/static init, or doesn't extend ImageNameSubstitutor.","commonSituations":"Typo in the fully-qualified class name; class moved/renamed after a refactor; config set locally but class lives only in another module; dependency not declared in the test classpath; constructor doing DI-dependent work.","solutions":["Verify the class name in ~/.testcontainers.properties matches a class on the test classpath, spelled correctly.","Ensure the class extends ImageNameSubstitutor and has a public no-arg constructor.","Remove the testcontainers.image.name.substitutor property if you don't need a custom substitutor.","Check the cause chain in the stack trace for the underlying load/instantiation failure (ClassNotFound vs Instantiation vs constructor exception)."],"exampleFix":"// before (testcontainers.properties)\ntestcontainers.image.name.substitutor=com.example.OldSubstitutor\n// after\ntestcontainers.image.name.substitutor=com.example.MyImageNameSubstitutor // existing, public, no-arg ctor","handlingStrategy":"validation","validationCode":"String cls = TestcontainersConfiguration.getInstance().getImageSubstitutorClassName();\nif (cls != null) {\n    Class<?> c = Class.forName(cls);\n    if (!ImageNameSubstitutor.class.isAssignableFrom(c)) throw new IllegalStateException(cls + \" must extend ImageNameSubstitutor\");\n    c.getDeclaredConstructor().setAccessible(true);\n}","typeGuard":null,"tryCatchPattern":"try {\n    ImageNameSubstitutor sub = ImageNameSubstitutor.instance();\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().startsWith(\"Configured Image Substitutor could not be loaded\")) {\n        log.error(\"Check testcontainers.image.name.substitutor: {}\", e.getMessage());\n    }\n    throw e;\n}","preventionTips":["Keep substitutor classes on the test classpath of every module using the property","Always provide a public no-arg constructor","Keep property value and class FQN in sync (avoid renames)","Add a smoke test that instantiates the configured substitutor"],"tags":["configuration","reflection","classpath"],"backgroundTag":"class-not-found","analyzedSha":"8e549514e3f01c57d70546fbb8599d138f3903e5","analyzedAt":"2026-09-12T14:56:41.227Z","contentChangedAt":"2026-09-12T14:56:41.227Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}