{"record":{"id":"084bcb7953ec3950","repo":"dianping/cat","slug":"object-keys-called-on-a-non-object","errorCode":null,"errorMessage":"Object.keys called on a non-object","messagePattern":"Object\\.keys called on a non-object","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"cat-home/src/main/webapp/assets/js/editor/worker-xquery.js","lineNumber":49448,"sourceCode":"            \"valueOf\",\n            \"hasOwnProperty\",\n            \"isPrototypeOf\",\n            \"propertyIsEnumerable\",\n            \"constructor\"\n        ],\n        dontEnumsLength = dontEnums.length;\n\n    for (var key in {\"toString\": null}) {\n        hasDontEnumBug = false;\n    }\n\n    Object.keys = function keys(object) {\n\n        if (\n            (typeof object != \"object\" && typeof object != \"function\") ||\n            object === null\n        ) {\n            throw new TypeError(\"Object.keys called on a non-object\");\n        }\n\n        var keys = [];\n        for (var name in object) {\n            if (owns(object, name)) {\n                keys.push(name);\n            }\n        }\n\n        if (hasDontEnumBug) {\n            for (var i = 0, ii = dontEnumsLength; i < ii; i++) {\n                var dontEnum = dontEnums[i];\n                if (owns(object, dontEnum)) {\n                    keys.push(dontEnum);\n                }\n            }\n        }\n        return keys;","sourceCodeStart":49430,"sourceCodeEnd":49466,"githubUrl":"https://github.com/dianping/cat/blob/e815e74d4c2dd74edac831241f1253fcc7d25381/cat-home/src/main/webapp/assets/js/editor/worker-xquery.js#L49430-L49466","documentation":"es5-shim's Object.keys polyfill validates that its argument is an object or function and throws this TypeError otherwise. Note that unlike the native ES5 Object.keys (which coerces primitives and allows strings, returning index keys), the shim rejects ALL primitives including strings, so behavior can differ between shimming and native environments. null and undefined always throw in both.","triggerScenarios":"Object.keys(null), Object.keys(undefined) (e.g. iterating an optional field that was never set), Object.keys(42). Object.keys('abc') works natively (returns ['0','1','2']) but throws under this shim on old engines — a real portability trap.","commonSituations":"Iterating over a config object that a previous step failed to populate; API responses where a field is null instead of {}; code developed on a modern browser (where Object.keys('str') silently works) then executed in the worker on a legacy engine.","solutions":["Default the value before iterating: Object.keys(obj || {}).","If strings can reach the call, convert explicitly: Object.keys(String(s).split('')) or gate on typeof first.","Trace why the value is null/undefined — usually an upstream missing assignment or a failed lookup."],"exampleFix":"// before\nvar keys = Object.keys(response.headers); // headers may be null\n\n// after\nvar keys = Object.keys(response.headers || {});","handlingStrategy":"validation","validationCode":"var keys = Object.keys(obj == null ? {} : (typeof obj === 'string' ? obj.split('') : obj));","typeGuard":"function isKeyable(v) {\n  return v !== null && v !== undefined && (typeof v === 'object' || typeof v === 'function' || typeof v === 'string');\n}","tryCatchPattern":null,"preventionTips":["Default before iterating: Object.keys(x || {})","Do not call Object.keys on strings if legacy engines must run the code","Initialize object fields to {} instead of leaving them null"],"tags":["es5-shim","object-keys","null-safety","polyfill","iteration"],"backgroundTag":null,"analyzedSha":"e815e74d4c2dd74edac831241f1253fcc7d25381","analyzedAt":"2026-08-14T14:22:34.512Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}