dianping/cat · error · TypeError

Object.keys called on a non-object

Error message

Object.keys called on a non-object

What it means

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.

Source

Thrown at cat-home/src/main/webapp/assets/js/editor/worker-xquery.js:49448

            "valueOf",
            "hasOwnProperty",
            "isPrototypeOf",
            "propertyIsEnumerable",
            "constructor"
        ],
        dontEnumsLength = dontEnums.length;

    for (var key in {"toString": null}) {
        hasDontEnumBug = false;
    }

    Object.keys = function keys(object) {

        if (
            (typeof object != "object" && typeof object != "function") ||
            object === null
        ) {
            throw new TypeError("Object.keys called on a non-object");
        }

        var keys = [];
        for (var name in object) {
            if (owns(object, name)) {
                keys.push(name);
            }
        }

        if (hasDontEnumBug) {
            for (var i = 0, ii = dontEnumsLength; i < ii; i++) {
                var dontEnum = dontEnums[i];
                if (owns(object, dontEnum)) {
                    keys.push(dontEnum);
                }
            }
        }
        return keys;

View on GitHub (pinned to e815e74d4c)

Solutions

  1. Default the value before iterating: Object.keys(obj || {}).
  2. If strings can reach the call, convert explicitly: Object.keys(String(s).split('')) or gate on typeof first.
  3. Trace why the value is null/undefined — usually an upstream missing assignment or a failed lookup.

Example fix

// before
var keys = Object.keys(response.headers); // headers may be null

// after
var keys = Object.keys(response.headers || {});
Defensive patterns

Strategy: validation

Validate before calling

var keys = Object.keys(obj == null ? {} : (typeof obj === 'string' ? obj.split('') : obj));

Type guard

function isKeyable(v) {
  return v !== null && v !== undefined && (typeof v === 'object' || typeof v === 'function' || typeof v === 'string');
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of dianping/cat@e815e74d4c (2026-08-14). Data as JSON: /api/errors/084bcb7953ec3950. Report an issue: GitHub.