{"record":{"id":"f4b229377e9a40ce","repo":"karatelabs/karate","slug":"ext-global-collides-with-built-in","errorCode":null,"errorMessage":"ext global '' collides with built-in ''","messagePattern":"ext global '' collides with built-in ''","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"karate-core/src/main/java/io/karatelabs/core/Suite.java","lineNumber":759,"sourceCode":"    // `match` is intentionally NOT reserved — core no longer ships a global `match` (assertions are the\n    // Gherkin `match` keyword + `karate.match`); a consumer may register its own `match` global.\n    private static final Set<String> RESERVED_GLOBAL_NAMES = Set.of(\"karate\", \"read\", \"driver\");\n\n    /**\n     * Register an ext global under {@code name}, seeded into every scenario's JS\n     * scope before {@code karate-config.js} evaluates. Called by an {@link Ext}\n     * from {@link Ext#onBoot(Suite)}; the instance is typically a\n     * {@link io.karatelabs.js.SimpleObject} so members cross into JS natively\n     * (no reflection). Throws — and so fails the Suite at boot — when the name is\n     * blank or collides with a built-in global ({@code karate}, {@code read},\n     * {@code match}, {@code driver}).\n     */\n    public void registerGlobal(String name, Object instance) {\n        if (name == null || name.isBlank()) {\n            throw new IllegalArgumentException(\"registerGlobal: name is null or empty\");\n        }\n        if (RESERVED_GLOBAL_NAMES.contains(name)) {\n            throw new RuntimeException(\"ext global '\" + name + \"' collides with built-in '\" + name + \"'\");\n        }\n        globals.put(name, instance);\n    }\n\n    /**\n     * Register a <em>per-scenario</em> ext global: the {@link ExtGlobalFactory} is\n     * invoked once per scenario at seed time to mint a fresh instance bound with the\n     * scenario's {@link KarateJsContext}. Prefer this over the singleton\n     * {@link #registerGlobal(String, Object)} when the global carries per-scenario\n     * mutable state or needs runtime / path access — see {@link ExtGlobalFactory}.\n     */\n    public void registerGlobal(String name, ExtGlobalFactory factory) {\n        if (name == null || name.isBlank()) {\n            throw new IllegalArgumentException(\"registerGlobal: name is null or empty\");\n        }\n        if (RESERVED_GLOBAL_NAMES.contains(name)) {\n            throw new RuntimeException(\"ext global '\" + name + \"' collides with built-in '\" + name + \"'\");\n        }","sourceCodeStart":741,"sourceCodeEnd":777,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-core/src/main/java/io/karatelabs/core/Suite.java#L741-L777","documentation":"Suite.registerGlobal(String, Object) rejects names that collide with Karate's built-in globals (karate, read, match, driver, etc., per RESERVED_GLOBAL_NAMES). The RuntimeException names both the attempted ext global and the built-in it would shadow. This protects script resolution: a user global must never silently override a built-in.","triggerScenarios":"Calling suite.registerGlobal(\"karate\", x), suite.registerGlobal(\"read\", x), etc. — any name contained in Suite.RESERVED_GLOBAL_NAMES. The template message shows the same name substituted twice ('ext global 'X' collides with built-in 'X'').","commonSituations":"Registering a helper class but passing the name \"karate\"; a generic registration loop that iterates over a map whose keys include reserved words; choosing short convenient names that happen to be built-ins after a Karate upgrade added new reserved names.","solutions":["Rename the global to something not in RESERVED_GLOBAL_NAMES (e.g. \"myKarate\" instead of \"karate\") and update script references","Check Suite.RESERVED_GLOBAL_NAMES in karate-core to see the full list of taken names","If registering many globals from a map, filter or prefix reserved keys before the loop"],"exampleFix":"// before\nsuite.registerGlobal(\"read\", new CustomReader());\n// after\nsuite.registerGlobal(\"customRead\", new CustomReader());","handlingStrategy":"validation","validationCode":"java.util.Set<String> reserved = java.util.Set.of(\"karate\",\"read\",\"match\",\"driver\");\nif (reserved.contains(name)) throw new IllegalArgumentException(\"name collides with built-in: \" + name);","typeGuard":null,"tryCatchPattern":"try { suite.registerGlobal(name, x); } catch (RuntimeException e) { /* collision: choose another name */ }","preventionTips":["Prefix user globals (e.g. 'my' or project code)","Check RESERVED_GLOBAL_NAMES when upgrading Karate","Avoid registering from unfiltered config key maps"],"tags":["java","configuration","naming-collision"],"backgroundTag":"invalid-argument-value","analyzedSha":"a22eb90246d958d15a47bf436693d0121ad2812d","analyzedAt":"2026-09-12T09:01:00.220Z","contentChangedAt":"2026-09-12T09:01:00.220Z","schemaVersion":2},"datasetVersion":"2026-09-19T12:17:13.211Z"}