{"record":{"id":"96fb031bc306febd","repo":"quarkusio/quarkus","slug":"openshift-operator-api-is-not-available-please-ad","errorCode":null,"errorMessage":"OpenShift Operator API is not available, please add the openshift-model-operator module to your classpath","messagePattern":"OpenShift Operator API is not available, please add the openshift-model-operator module to your classpath","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"extensions/openshift-client/runtime/src/main/java/io/quarkus/it/openshift/client/runtime/graal/OperatorSubstitutions.java","lineNumber":28,"sourceCode":"import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation;\nimport io.fabric8.kubernetes.client.dsl.Resource;\nimport io.fabric8.openshift.api.model.operator.imageregistry.v1.Config;\nimport io.fabric8.openshift.api.model.operator.imageregistry.v1.ConfigList;\nimport io.fabric8.openshift.api.model.operator.network.v1.EgressRouter;\nimport io.fabric8.openshift.api.model.operator.network.v1.EgressRouterList;\nimport io.fabric8.openshift.api.model.operator.network.v1.OperatorPKI;\nimport io.fabric8.openshift.api.model.operator.network.v1.OperatorPKIList;\nimport io.fabric8.openshift.client.dsl.OpenShiftOperatorAPIGroupDSL;\n\n/**\n * Allows the exclusion of the openshift-model-operator model without breaking the --link-at-build-time check.\n */\n@TargetClass(className = \"io.fabric8.openshift.client.impl.OpenShiftClientImpl\", onlyWith = OperatorSubstitutions.NoOpenShiftOperatorModel.class)\npublic final class OperatorSubstitutions {\n\n    @Substitute\n    public MixedOperation<EgressRouter, EgressRouterList, Resource<EgressRouter>> egressRouters() {\n        throw new RuntimeException(OperatorSubstitutions.Constants.ERROR_MESSAGE);\n    }\n\n    @Substitute\n    public NonNamespaceOperation<Config, ConfigList, Resource<Config>> imageRegistryOperatorConfigs() {\n        throw new RuntimeException(OperatorSubstitutions.Constants.ERROR_MESSAGE);\n    }\n\n    @Substitute\n    public OpenShiftOperatorAPIGroupDSL operator() {\n        throw new RuntimeException(OperatorSubstitutions.Constants.ERROR_MESSAGE);\n    }\n\n    @Substitute\n    public MixedOperation<OperatorPKI, OperatorPKIList, Resource<OperatorPKI>> operatorPKIs() {\n        throw new RuntimeException(OperatorSubstitutions.Constants.ERROR_MESSAGE);\n    }\n\n    static final class Constants {","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/openshift-client/runtime/src/main/java/io/quarkus/it/openshift/client/runtime/graal/OperatorSubstitutions.java#L10-L46","documentation":"This substitution in Quarkus's openshift-client extension replaces fabric8 OpenShiftClientImpl methods that require the OpenShift Operator model at native-image build time. When the openshift-model-operator module is not on the classpath, calling egressRouters() throws a RuntimeException instead of failing with a linkage error. It is a GraalVM native-image @TargetClass substitution guarding an optional dependency.","triggerScenarios":"Calling OpenShiftClient.egressRouters() in a native-image build (or build-time-substituted context) when io.fabric8:openshift-model-operator is absent from the classpath.","commonSituations":"Users of the Quarkus openshift-client extension who interact with OpenShift Operator resources (EgressRouter, OperatorPKI, image registry configs) but only added the base openshift-client dependency; the app works in JVM mode but fails at runtime in native mode.","solutions":["Add io.quarkus:quarkus-openshift-client plus the fabric8 openshift-model-operator dependency (quarkus-openshift-client brings it transitively when the operator model flavor is used) to the project's pom.xml","Verify the app is not depending on an old/bom-pinned fabric8 version that excludes openshift-model-operator","If Operator APIs are not needed, avoid calling egressRouters()/operator() style methods"],"exampleFix":"// before\n<dependency>\n  <groupId>io.quarkus</groupId>\n  <artifactId>quarkus-openshift-client</artifactId>\n</dependency>\n// after\n<dependency>\n  <groupId>io.quarkus</groupId>\n  <artifactId>quarkus-openshift-client</artifactId>\n</dependency>\n<!-- operator model available transitively; if excluded, re-add -->\n<dependency>\n  <groupId>io.fabric8</groupId>\n  <artifactId>openshift-model-operator</artifactId>\n</dependency>","handlingStrategy":"validation","validationCode":"// before calling egressRouters(), verify the model is on the classpath\nstatic boolean operatorModelAvailable() {\n    try {\n        Class.forName(\"io.fabric8.openshift.client.dsl.OpenShiftOperatorAPIGroupDSL\");\n        return true;\n    } catch (ClassNotFoundException e) {\n        return false;\n    }\n}","typeGuard":"static boolean canUseOperatorApis(OpenShiftClient client) {\n    return client instanceof OpenShiftClientImpl\n        && operatorModelAvailable();\n}","tryCatchPattern":"try {\n    client.egressRouters().inAnyNamespace().list();\n} catch (RuntimeException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"openshift-model-operator\")) {\n        throw new IllegalStateException(\"Add io.fabric8:openshift-model-operator to the classpath\", e);\n    }\n    throw e;\n}","preventionTips":["Always add io.fabric8:openshift-model-operator when using Operator/OperatorPKI/EgressRouter APIs","Test the native build early — these substitutions only fail in native mode","Import the Quarkus BOM so fabric8 modules stay version-aligned","Grep the codebase for OpenShift Operator APIs before removing 'unused' dependencies"],"tags":["native-image","openshift","missing-dependency","classpath"],"backgroundTag":"missing-native-image-dependency","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}