{"record":{"id":"38e327862a5dd8a1","repo":"karatelabs/karate","slug":"cannot-read-properties-of-null-undefined-reading","errorCode":null,"errorMessage":"cannot read properties of ${null|undefined} (reading ...)","messagePattern":"cannot read properties of (.+?) \\(reading \\.\\.\\.\\)","errorType":"exception","errorClass":"JsErrorException (typeError)","httpStatus":null,"severity":"error","filePath":"karate-js/src/main/java/io/karatelabs/js/PropertyAccess.java","lineNumber":427,"sourceCode":"                    if (context.isStopped()) yield null;\n                    context.updateSlot(slot, newValue, trackingNode);\n                    yield newValue;\n                }\n                yield logicalCompoundRefByName(node, context, operator, rhsNode, trackingNode);\n            }\n            case REF_DOT_EXPR, REF_BRACKET_EXPR -> {\n                AccessSite site = resolveWriteSite(node, context);\n                if (site == null || site == SHORT_CIRCUIT_SITE) yield Terms.UNDEFINED;\n                // JS-level throw inside the target or index eval surfaces as\n                // context.isStopped() (eval returns null on abrupt completion).\n                // Bail before doing any further checks so the in-flight throw\n                // — not our own TypeError — is what the catch sees.\n                if (context.isStopped()) yield null;\n                // RequireObjectCoercible fires before ToPropertyKey on the index —\n                // null/undefined target must throw TypeError before any toString\n                // on a non-primitive key is invoked.\n                if (site.target == null || site.target == Terms.UNDEFINED) {\n                    throw JsErrorException.typeError(\"cannot read properties of \"\n                            + (site.target == null ? \"null\" : \"undefined\"));\n                }\n                if (site.privateName != null) {\n                    Object oldValue = PrivateAccess.get(site.target, site.privateName, context);\n                    if (!shouldLogicalAssign(operator, oldValue)) yield oldValue;\n                    Object newValue = Interpreter.eval(rhsNode, context);\n                    if (context.isStopped()) yield null;\n                    PrivateAccess.set(site.target, site.privateName, newValue, context);\n                    yield newValue;\n                }\n                if (site.receiver != null) {\n                    // super reference — the fused by-index/by-name workers\n                    // below have no receiver seam; run the generic sequence.\n                    Object oldValue = siteRead(site, context);\n                    if (context.isStopped()) yield null;\n                    if (!shouldLogicalAssign(operator, oldValue)) yield oldValue;\n                    Object newValue = Interpreter.eval(rhsNode, context);\n                    if (context.isStopped()) yield null;","sourceCodeStart":409,"sourceCodeEnd":445,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-js/src/main/java/io/karatelabs/js/PropertyAccess.java#L409-L445","documentation":"A TypeError mirroring the browser message 'cannot read properties of null/undefined', thrown when the target of a logical assignment (`||=`, `&&=`, `??=`) through a dot or bracket access is null or undefined. RequireObjectCoercible fires before any key conversion, so `obj?.x ??= v` on a missing base throws rather than silently skipping.","triggerScenarios":"`a.b ||= value` (or `&&=`/`??=`) where `a` evaluates to null or undefined — e.g. reading a nested config path that was never set, or an API response missing the intermediate object.","commonSituations":"Optional-chaining used for reads but not for the assignment target (`a?.b ??= v` still throws when `a` is undefined since the chain short-circuits to undefined, not a reference); JSON fixtures missing a nested level; map lookups returning null.","solutions":["Guard the base object first: `if (a) a.b ??= value;`","Provide defaults at the root: `const a = raw ?? {};` before nested logical assignments","Use explicit optional chaining plus separate assignment: `if (a?.b == null && a) a.b = value;`","Fix the data source so the intermediate object is always present"],"exampleFix":"// before\nconfig.redis ??= { host: 'localhost' };\n// after\nconfig = config ?? {};\nconfig.redis ??= { host: 'localhost' };","handlingStrategy":"type-guard","validationCode":"// JS in the script, before the logical assignment\nif (config == null) config = {};\nif (config.redis == null) config.redis = {};","typeGuard":"function hasBase(obj, path) {\n  return path.split('.').every(seg => (obj = obj?.[seg]) !== null && obj !== undefined) || obj !== undefined;\n}\n// simpler precheck:\nfunction isObject(v) { return v !== null && typeof v === 'object'; }","tryCatchPattern":"try {\n  evalScript(\"config.redis ??= { host: 'localhost' };\");\n} catch (JsErrorException e) {\n  if (e.getMessage().startsWith(\"cannot read properties of\")) {\n    evalScript(\"config = config ?? {}; config.redis ??= { host: 'localhost' };\");\n  } else throw e;\n}","preventionTips":["Initialize nested object shells before applying nested logical assignments","Validate JSON fixtures for required intermediate keys before use","Use optional chaining for reads and guard before writing","Centralize a `ensurePath(obj, 'a.b.c')` helper in test setups"],"tags":["javascript","null-pointer","logical-assignment"],"backgroundTag":"cannot-read-properties-of-null","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"}