{"record":{"id":"5f582149233e6120","repo":"karatelabs/karate","slug":"cannot-destructure-source","errorCode":null,"errorMessage":"cannot destructure ${source}","messagePattern":"cannot destructure (.+?)","errorType":"exception","errorClass":"JsErrorException","httpStatus":null,"severity":"error","filePath":"karate-js/src/main/java/io/karatelabs/js/Interpreter.java","lineNumber":275,"sourceCode":"    }\n\n    /**\n     * Walk a destructuring pattern (LIT_ARRAY or LIT_OBJECT) and bind each leaf\n     * target from the corresponding piece of `source`. When `bindScope` is\n     * non-null the pattern is a declaration (`var/let/const [a] = ...`) and\n     * leaves are declared; when null it is an assignment expression\n     * (`[a] = ...`) and leaves are updated / applied via `PropertyAccess.set`.\n     * Nested patterns recurse; default values fire only when the corresponding\n     * source value is undefined.\n     */\n    @SuppressWarnings(\"unchecked\")\n    private static void destructurePattern(Node pattern, CoreContext context,\n                                            BindScope bindScope, Object source, boolean initialized) {\n        // Per spec 13.3.3.5: destructuring null/undefined throws TypeError.\n        // ArrayBindingPattern calls GetIterator(value); ObjectBindingPattern\n        // calls RequireObjectCoercible(value); both fail for null/undefined.\n        if (source == null || source == Terms.UNDEFINED) {\n            throw JsErrorException.typeError(\"cannot destructure \" + source);\n        }\n        if (pattern.type == NodeType.LIT_ARRAY) {\n            // Array destructuring per spec 13.3.3.5 calls GetIterator(value).\n            // Pull through the unified iterator surface — IterUtils throws TypeError\n            // for non-iterables (boolean, plain object without @@iterator, etc.).\n            JsIterator iter = IterUtils.getIterator(source, context);\n            int last = pattern.size() - 1;\n            // Per spec 13.15.5.3 / 8.5.2: when the pattern finishes with the iterator\n            // not yet exhausted (no rest element, or a rest never reached), perform\n            // IteratorClose(iterator). A rest element drives next() to done, so close\n            // then no-ops. On an abrupt completion (a binding / default expr throws),\n            // IteratorClose still runs but the original throw wins.\n            boolean abrupt = false;\n            try {\n                for (int i = 1; i < last; i++) {\n                    Node elem = pattern.get(i);\n                    Node first = elem.get(0);\n                    if (first.isToken() && first.token.type == DOT_DOT_DOT) {","sourceCodeStart":257,"sourceCodeEnd":293,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-js/src/main/java/io/karatelabs/js/Interpreter.java#L257-L293","documentation":"Per ECMAScript 13.3.3.5, destructuring null or undefined throws a TypeError; Interpreter.destructurePattern raises this with the offending value in the message. Array patterns would call GetIterator and object patterns RequireObjectCoercible — both impossible for null/undefined — so the engine fails early with a clear message instead.","triggerScenarios":"`var {a, b} = someVar` or `var [x, y] = someVar` where someVar is null or undefined — commonly an unset karate variable, a missing JSON path (`response.data` when absent), or a function returning undefined.","commonSituations":"Destructuring an API response field that is absent; karate variable never set before the script runs; optional chaining omitted (`res.user` is undefined when user is missing); schema drift where a previously-present field disappears.","solutions":["Default the source: `var {a} = maybeNull || {}` or `var [x] = maybeArr || []`","Guard with a null check before destructuring","Fix the upstream producer so it returns a real object/array","Use karate's safe navigation / isNull checks before the destructuring statement"],"exampleFix":"// before\nvar { name, age } = response.user;\n// after\nvar { name, age } = response.user || {};","handlingStrategy":"validation","validationCode":"const src = response.user || {};\nvar { name, age } = src;","typeGuard":"function isDestructurable(x) { return x != null && (typeof x === 'object' || typeof x[Symbol.iterator] === 'function'); }","tryCatchPattern":"try { var { a } = src; } catch (e) { if (String(e).includes('cannot destructure')) { /* fall back to defaults */ } else { throw e; } }","preventionTips":["Always provide || {} / || [] defaults on possibly-missing sources","Validate response shapes before destructuring","Use safe navigation for nested paths"],"tags":["javascript","destructuring","typeerror","null","undefined"],"backgroundTag":"type-mismatch","analyzedSha":"a22eb90246d958d15a47bf436693d0121ad2812d","analyzedAt":"2026-09-12T09:01:00.220Z","contentChangedAt":"2026-09-12T09:01:00.220Z","schemaVersion":2},"datasetVersion":"2026-09-16T19:17:19.609Z"}