karatelabs/karate · error · JsErrorException

Reflect.ownKeys called on non-object

Error message

Reflect.ownKeys called on non-object

What it means

`Reflect.ownKeys(target)` implements [[OwnPropertyKeys]] and, per spec, requires an Object target. Karate's `ownKeys` throws this TypeError when the first argument is missing or not an ObjectLike (a string, number, null, undefined, etc.).

Solutions

  1. Pass an actual object: `Reflect.ownKeys(obj)`.
  2. Guard beforehand: `if (target && typeof target === 'object') Reflect.ownKeys(target)`.
  3. For primitives, use `Object.keys(Object(primitive))` semantics explicitly if that's the intent.

Example fix

// before
const keys = Reflect.ownKeys(maybeObject); // may be undefined
// after
const keys = maybeObject != null && typeof maybeObject === 'object' ? Reflect.ownKeys(maybeObject) : [];
Defensive patterns

Strategy: type-guard

Validate before calling

function ownKeysSafe(target) {
  if (target == null || (typeof target !== 'object' && typeof target !== 'function')) return [];
  return Reflect.ownKeys(target);
}

Type guard

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

Try / catch

try { return Reflect.ownKeys(target); } catch (e) { if (e instanceof TypeError && /ownKeys called on non-object/.test(e.message)) return []; throw e; }

Prevention

When it happens

Trigger: `Reflect.ownKeys()` with no args; `Reflect.ownKeys('abc')`, `Reflect.ownKeys(42)`, `Reflect.ownKeys(null)`; passing a Java-side non-object value into the JS call.

Common situations: Reflected/introspective code fed by dynamic data where the value unexpectedly became a primitive; forwarding undefined from an earlier failed lookup.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12). Data as JSON: /api/errors/1b05a9d602ac90a8. Report an issue: GitHub.

Appendix: source

Thrown at karate-js/src/main/java/io/karatelabs/js/JsReflect.java:52

class JsReflect extends JsObject {

    @Override
    protected Object resolveOwnIntrinsic(String name) {
        return switch (name) {
            case "construct" -> (JsCallable) this::construct;
            case "apply" -> (JsCallable) this::apply;
            case "ownKeys" -> (JsCallable) this::ownKeys;
            default -> null;
        };
    }

    private static final List<String> INTRINSIC_NAMES = List.of("construct", "apply", "ownKeys");

    /** §28.1.11 — [[OwnPropertyKeys]] in spec order: string keys, then the
     *  symbol values from the object's symbol store. */
    private Object ownKeys(Context context, Object[] args) {
        if (args.length < 1 || !(args[0] instanceof ObjectLike target)) {
            throw JsErrorException.typeError("Reflect.ownKeys called on non-object");
        }
        // §10.1.11.1 OrdinaryOwnPropertyKeys: integer indices ascending, then
        // strings in insertion order — the same helper Object.keys uses.
        // named half only for an array — toMap()'s index keys include holes,
        // and the spec index+length key set for arrays is a separate gap here
        List<Object> keys = new java.util.ArrayList<>(JsObject.orderedOwnKeys(
                target instanceof JsArray ja ? ja.namedPropsView().keySet() : target.toMap().keySet()));
        if (target instanceof JsObject jo) {
            keys.addAll(jo.ownSymbols());
        }
        return new JsArray(keys);
    }

    @Override
    protected Iterable<String> ownIntrinsicNames() {
        return INTRINSIC_NAMES;
    }

View on GitHub (pinned to a22eb90246)