{"record":{"id":"c442b2042aab78d6","repo":"nodejs/node","slug":"expected-key-to-be-object-got-typeof-key-c442b2","errorCode":null,"errorMessage":"expected key to be object, got ${typeof key}","messagePattern":"expected key to be object, got (.+?)","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"deps/undici/src/lib/cache/sqlite-cache-store.js","lineNumber":348,"sourceCode":"        } else {\n          this.destroy()\n        }\n\n        callback()\n      },\n      final (callback) {\n        store.set(key, { ...value, body })\n        callback()\n      }\n    })\n  }\n\n  /**\n   * @param {import('../../types/cache-interceptor.d.ts').default.CacheKey} key\n   */\n  delete (key) {\n    if (typeof key !== 'object') {\n      throw new TypeError(`expected key to be object, got ${typeof key}`)\n    }\n\n    this.#deleteByUrlQuery.run(this.#makeValueUrl(key))\n  }\n\n  #prune () {\n    if (Number.isFinite(this.#maxCount) && this.size <= this.#maxCount) {\n      return 0\n    }\n\n    {\n      const removed = this.#deleteExpiredValuesQuery.run(Date.now()).changes\n      if (removed) {\n        return removed\n      }\n    }\n\n    {","sourceCodeStart":330,"sourceCodeEnd":366,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/deps/undici/src/lib/cache/sqlite-cache-store.js#L330-L366","documentation":"Thrown by SqliteCacheStore.delete() when the supplied key is not an object. The store expects a CacheKey (the typed import is import('../../types/cache-interceptor.d.ts').default.CacheKey) and uses key fields to build the value URL via #makeValueUrl(key), so a primitive cannot work.","triggerScenarios":"Calling sqliteStore.delete('https://x/y'), delete(null), delete(undefined), or delete(42). Reproduces in custom store wrappers or tests that forward a URL string instead of the structured key.","commonSituations":"Treating the SQLite store like a key-value map keyed by URL string; reusing a fetch Cache API mental model where the URL is the key; refactoring that loses the key object.","solutions":["Pass a CacheKey object: delete({ origin, method, path, headers }).","If you only have a URL, parse it and assemble the key with origin + pathname.","Drive deletes through the CacheInterceptor so the key shape is correct by construction.","Add a typeof key === 'object' guard in your own wrapper to fail before the store."],"exampleFix":"// before\nstore.delete('https://example.com/api')\n// after\nconst u = new URL('https://example.com/api')\nstore.delete({ origin: u.origin, method: 'GET', path: u.pathname })","handlingStrategy":"type-guard","validationCode":"if (key == null || typeof key !== 'object') {\n  throw new TypeError('cache key must be an object')\n}\nstore.delete(key)","typeGuard":"function isCacheKey(k) {\n  return k != null && typeof k === 'object'\n    && typeof k.origin === 'string'\n    && typeof k.method === 'string'\n    && typeof k.path === 'string'\n}","tryCatchPattern":"try {\n  store.delete(key)\n} catch (err) {\n  if (err instanceof TypeError && /expected key to be object/.test(err.message)) {\n    log.warn('ignoring malformed cache key', key)\n  } else throw err\n}","preventionTips":["Route deletes through the CacheInterceptor.","Centralize CacheKey construction in one helper.","Type your key with the CacheKey interface.","Test your wrapper with string and null inputs."],"tags":["cache","sqlite","validation","type-error","undici"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}