{"record":{"id":"7d7fd0569a70e891","repo":"testcontainers/testcontainers-java","slug":"failed-to-verify-that-image-s-is-a-compatible-substitute-for","errorCode":null,"errorMessage":"Failed to verify that image '%s' is a compatible substitute for '%s'. This generally means that you are trying to use an image that Testcontainers has not been designed to use. If this is deliberate, and if you are confident that the image is compatible, you should declare compatibility in code using the `asCompatibleSubstituteFor` method. For example:\n   DockerImageName myImage = DockerImageName.parse(\"%s\").asCompatibleSubstituteFor(\"%s\");\nand then use `myImage` instead.","messagePattern":"Failed to verify that image '(.+?)' is a compatible substitute for '(.+?)'\\. This generally means that you are trying to use an image that Testcontainers has not been designed to use\\. If this is deliberate, and if you are confident that the image is compatible, you should declare compatibility in code using the `asCompatibleSubstituteFor` method\\. For example:\n   DockerImageName myImage = DockerImageName\\.parse\\(\"(.+?)\"\\)\\.asCompatibleSubstituteFor\\(\"(.+?)\"\\);\nand then use `myImage` instead\\.","errorType":"exception","errorClass":"java.lang.IllegalStateException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/testcontainers/utility/DockerImageName.java","lineNumber":309,"sourceCode":"     *                  than one is provided, this method will check compatibility with at least one\n     *                  of them.\n     * @throws IllegalStateException if {@link DockerImageName#isCompatibleWith(DockerImageName)}\n     *                               returns false\n     */\n    public void assertCompatibleWith(DockerImageName... anyOthers) {\n        if (anyOthers.length == 0) {\n            throw new IllegalArgumentException(\"anyOthers parameter must be non-empty\");\n        }\n\n        for (DockerImageName anyOther : anyOthers) {\n            if (this.isCompatibleWith(anyOther)) {\n                return;\n            }\n        }\n\n        final DockerImageName exampleOther = anyOthers[0];\n\n        throw new IllegalStateException(\n            String.format(\n                \"Failed to verify that image '%s' is a compatible substitute for '%s'. This generally means that \" +\n                \"you are trying to use an image that Testcontainers has not been designed to use. If this is \" +\n                \"deliberate, and if you are confident that the image is compatible, you should declare \" +\n                \"compatibility in code using the `asCompatibleSubstituteFor` method. For example:\\n\" +\n                \"   DockerImageName myImage = DockerImageName.parse(\\\"%s\\\").asCompatibleSubstituteFor(\\\"%s\\\");\\n\" +\n                \"and then use `myImage` instead.\",\n                this.rawName,\n                exampleOther.rawName,\n                this.rawName,\n                exampleOther.rawName\n            )\n        );\n    }\n}\n","sourceCodeStart":291,"sourceCodeEnd":325,"githubUrl":"https://github.com/testcontainers/testcontainers-java/blob/8e549514e3f01c57d70546fbb8599d138f3903e5/core/src/main/java/org/testcontainers/utility/DockerImageName.java#L291-L325","documentation":"assertCompatibleWith verifies that the image being used is compatible with an image Testcontainers was designed for (same repository, or declared via asCompatibleSubstituteFor). If no candidate matches, it throws IllegalStateException with a long explanation and a code example showing how to declare compatibility. This prevents silently running an incompatible drop-in image against container-specific logic.","triggerScenarios":"Starting a container module with a substitute image whose repository differs from the expected one without calling asCompatibleSubstituteFor, e.g. new PostgreSQLContainer(DockerImageName.parse(\"myregistry/postgres-mirror:16\")) — a mirror with a non-matching repo name.","commonSituations":"Using private registry mirrors or proxies whose full name doesn't end with the expected repo (e.g. 'docker.mycorp.io/postgres' parses differently than expected); using lookalike images (mysql for mariadb and vice versa); vendor forks named differently.","solutions":["If the image truly is a compatible substitute, declare it: DockerImageName.parse(\"myimage\").asCompatibleSubstituteFor(\"postgres\") and pass the result to the container.","If using a registry mirror, check the container module's mirror-configuration support (e.g. TestcontainersConfiguration or the module's image constant) so the expected repo is matched against your mirror.","If the image genuinely differs, use the correct Testcontainers module or a GenericContainer instead of forcing substitution."],"exampleFix":"// before\nnew PostgreSQLContainer(DockerImageName.parse(\"registry.mycorp.io/pg-mirror:16\"));\n// after\nnew PostgreSQLContainer(\n    DockerImageName.parse(\"registry.mycorp.io/pg-mirror:16\").asCompatibleSubstituteFor(\"postgres\"));","handlingStrategy":"try-catch","validationCode":"DockerImageName parsed = DockerImageName.parse(raw);\nif (!parsed.isCompatibleWith(DockerImageName.parse(\"postgres\"))) {\n    parsed = parsed.asCompatibleSubstituteFor(\"postgres\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    container.start();\n} catch (IllegalStateException e) {\n    if (e.getMessage().startsWith(\"Failed to verify that image\")) {\n        log.error(\"Incompatible substitute image; declare via asCompatibleSubstituteFor\");\n    }\n    throw e;\n}","preventionTips":["Always wrap registry-mirror images with asCompatibleSubstituteFor","Use isCompatibleWith in tests to assert image choices","Keep mirror names in config rather than changing repository paths"],"tags":["compatibility","docker-image","substitution"],"backgroundTag":"incompatible-source-type","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"}