{"record":{"id":"cd79ed02c0e0576c","repo":"karatelabs/karate","slug":"cannot-convert-object-to-primitive-value","errorCode":null,"errorMessage":"Cannot convert object to primitive value","messagePattern":"Cannot convert object to primitive value","errorType":"exception","errorClass":"JsErrorException (typeError)","httpStatus":null,"severity":"error","filePath":"karate-js/src/main/java/io/karatelabs/js/Terms.java","lineNumber":1358,"sourceCode":"        // (\"string\" | \"number\" | \"default\"). Result must be a primitive; an object result\n        // is a TypeError per spec. Set-but-not-callable is also a TypeError (GetMethod).\n        Object exotic = ol.getMember(\"@@toPrimitive\");\n        if (exotic != null && exotic != UNDEFINED) {\n            if (!(exotic instanceof JsCallable jsc)) {\n                throw JsErrorException.typeError(\"Symbol.toPrimitive method is not callable\");\n            }\n            CoreContext callCtx = new CoreContext(context, null, null);\n            callCtx.thisObject = ol;\n            String hintArg = hint == null ? \"default\" : hint;\n            Object r = jsc.call(callCtx, new Object[]{hintArg});\n            if (callCtx.isError()) {\n                context.updateFrom(callCtx);\n                return UNDEFINED;\n            }\n            if (r == null || r == UNDEFINED || isPrimitive(r) || r instanceof BigInteger) {\n                return r;\n            }\n            throw JsErrorException.typeError(\"Cannot convert object to primitive value\");\n        }\n        return ordinaryToPrimitive(ol, hint, context);\n    }\n\n    /**\n     * Spec §7.1.1.1 OrdinaryToPrimitive — the valueOf/toString-only dispatch\n     * without the @@toPrimitive check. Used by {@link #toPrimitive} as the\n     * fallback path, and by built-in @@toPrimitive methods (e.g. Date) that\n     * need to invoke OrdinaryToPrimitive on themselves without re-entering\n     * the @@toPrimitive lookup.\n     */\n    static Object ordinaryToPrimitive(ObjectLike ol, String hint, CoreContext context) {\n        String[] order = \"string\".equals(hint)\n                ? new String[]{\"toString\", \"valueOf\"}\n                : new String[]{\"valueOf\", \"toString\"};\n        for (String methodName : order) {\n            Object fn = ol.getMember(methodName);\n            if (!(fn instanceof JsCallable jsc)) {","sourceCodeStart":1340,"sourceCodeEnd":1376,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-js/src/main/java/io/karatelabs/js/Terms.java#L1340-L1376","documentation":"If an object's @@toPrimitive method returns an object (not a primitive), the spec says ToPrimitive fails with a TypeError. Terms.java enforces this: only null, undefined, primitives, or BigInt results are accepted from the exotic conversion path.","triggerScenarios":"An object whose Symbol.toPrimitive function returns an object/array/another object, then that object is coerced (arithmetic, `+`, comparison, template string) in karate-js.","commonSituations":"Returning `this` or a wrapped value from a custom toPrimitive; returning a boxed Number/String object instead of a raw primitive.","solutions":["Return a primitive from the toPrimitive callback (string, number, or bigint)","Unwrap boxed results: return Number(x) or String(x) instead of a boxed object","Fall back to valueOf/toString (delete the exotic method) if a primitive result can't be produced"],"exampleFix":"// before\nconst o = { [Symbol.toPrimitive]: (h) => ({ value: 1 }) };\n// after\nconst o = { [Symbol.toPrimitive]: (h) => 1 };","handlingStrategy":"try-catch","validationCode":"const tp = obj && obj[Symbol.toPrimitive];\nif (typeof tp === 'function') { const r = tp.call(obj, 'default'); if (r !== null && typeof r === 'object') throw new Error('toPrimitive must return a primitive'); }","typeGuard":null,"tryCatchPattern":"try { v = coerce(obj); } catch (e) { if (String(e).includes('convert object to primitive')) v = String(JSON.stringify(obj)); else throw e; }","preventionTips":["Always return a primitive from Symbol.toPrimitive callbacks","Unwrap boxed Number/String results before returning","Test custom valueOf/toString/toPrimitive implementations with + and template literals"],"tags":["javascript","to-primitive","coercion"],"backgroundTag":"unexpected-response-shape","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"}