{"record":{"id":"3c0642d4c11567be","repo":"jestjs/jest","slug":"cannot-use-spyon-on-a-primitive-value-this-typ","errorCode":null,"errorMessage":"Cannot use spyOn on a primitive value; ${this._typeOf(object)} given","messagePattern":"Cannot use spyOn on a primitive value; (.+?) given","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/jest-mock/src/index.ts","lineNumber":1280,"sourceCode":"  spyOn<\n    T extends object,\n    K extends ConstructorLikeKeys<T> | MethodLikeKeys<T>,\n    V extends Required<T>[K],\n  >(\n    object: T,\n    methodKey: K,\n  ): V extends ClassLike | FunctionLike ? Spied<V> : never;\n\n  spyOn<T extends object>(\n    object: T,\n    methodKey: keyof T,\n    accessType?: 'get' | 'set',\n  ): MockInstance {\n    if (\n      object == null ||\n      (typeof object !== 'object' && typeof object !== 'function')\n    ) {\n      throw new Error(\n        `Cannot use spyOn on a primitive value; ${this._typeOf(object)} given`,\n      );\n    }\n\n    if (methodKey == null) {\n      throw new Error('No property name supplied');\n    }\n\n    if (accessType) {\n      return this._spyOnProperty(object, methodKey, accessType);\n    }\n\n    const original = object[methodKey];\n\n    if (!original) {\n      throw new Error(\n        `Property \\`${String(\n          methodKey,","sourceCodeStart":1262,"sourceCodeEnd":1298,"githubUrl":"https://github.com/jestjs/jest/blob/8e6d128e4a278059ecddecaa97400b04c8ae5fd9/packages/jest-mock/src/index.ts#L1262-L1298","documentation":"Thrown by jest.spyOn when the first argument is null, undefined, or a JS primitive (number/string/boolean/symbol). spyOn can only attach a spy to an object or function, so the guard rejects non-object targets up front.","triggerScenarios":"jest.spyOn(null,'foo'); jest.spyOn(undefined,'bar'); jest.spyOn('hello','length'); jest.spyOn(42,'toString'); jest.spyOn(true,'valueOf').","commonSituations":"The module/object import resolved to undefined (wrong path, named/default mismatch, ESM vs CJS interop); spying on a re-export that lost the object; tree-shaking removed the binding; passing a destructured primitive instead of the holder object.","solutions":["Log the first argument to confirm it is an object/function at runtime.","Fix the import (named vs default, correct relative path, check the module's exports field).","Spy on the object that owns the method (e.g. the module namespace object) rather than a primitive it exports."],"exampleFix":"// before\njest.spyOn(logger, 'info');  // logger is undefined because of wrong import\n// after\nimport * as logger from './logger';\njest.spyOn(logger, 'info');","handlingStrategy":"type-guard","validationCode":"if (target == null || (typeof target !== 'object' && typeof target !== 'function')) {\n  throw new TypeError(`spyOn target must be an object/function, got ${typeof target}`);\n}\njest.spyOn(target, methodName);","typeGuard":"const isSpyable = (x: unknown): x is object =>\n  x != null && (typeof x === 'object' || typeof x === 'function');","tryCatchPattern":null,"preventionTips":["Log the import you intend to spy on before calling spyOn.","Prefer spying on module namespace objects (import * as) for stable references.","Verify named vs default exports match your import style."],"tags":["spy","mock","type-validation"],"backgroundTag":null,"analyzedSha":"8e6d128e4a278059ecddecaa97400b04c8ae5fd9","analyzedAt":"2026-08-10T18:11:27.960Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}