nodejs/node · error · TypeError

expected key to be object, got ${typeof key}

Error message

expected key to be object, got ${typeof key}

What it means

Thrown by MemoryCacheStore.delete() when the supplied key is not an object. The interceptor's cache key is a structured object carrying at least origin and path (delete composes `${key.origin}:${key.path}` as the top-level lookup), so a primitive cannot be used. It is a TypeError because the contract of the store API was violated, not a network/runtime failure.

Source

Thrown at deps/undici/src/lib/cache/memory-cache-store.js:207

          }

          // Reset the event flag after eviction
          if (store.#size < store.#maxSize && store.#count < store.#maxCount) {
            store.#hasEmittedMaxSizeEvent = false
          }
        }

        callback(null)
      }
    })
  }

  /**
   * @param {CacheKey} key
   */
  delete (key) {
    if (typeof key !== 'object') {
      throw new TypeError(`expected key to be object, got ${typeof key}`)
    }

    const topLevelKey = `${key.origin}:${key.path}`

    for (const entry of this.#entries.get(topLevelKey) ?? []) {
      this.#size -= entry.size
      this.#count -= 1
    }
    this.#entries.delete(topLevelKey)
  }
}

function findEntry (key, entries, now) {
  for (let i = 0; i < entries.length; i++) {
    const entry = entries[i]
    if (
      entry.deleteAt > now &&
      entry.method === key.method &&

View on GitHub (pinned to 1b2de5e052)

Solutions

  1. Pass an object containing at least origin and path, e.g. delete({ origin: 'https://example.com', method: 'GET', path: '/users' }).
  2. If you hold a Request/URL, build the key from url.origin + url.pathname + url.search before calling delete.
  3. If integrating with the CacheInterceptor, never call store methods yourself — let the interceptor build the key.
  4. Add a typeof key === 'object' guard in your wrapper to fail loudly before reaching the store.

Example fix

// before
store.delete('https://example.com/users')
// after
store.delete({
  origin: 'https://example.com',
  method: 'GET',
  path: '/users'
})
Defensive patterns

Strategy: type-guard

Validate before calling

if (key == null || typeof key !== 'object' || typeof key.origin !== 'string' || typeof key.path !== 'string') {
  throw new TypeError('cache key must be an object with origin and path strings')
}
store.delete(key)

Type guard

function isCacheKey(k) {
  return k != null && typeof k === 'object'
    && typeof k.origin === 'string'
    && typeof k.path === 'string'
    && typeof k.method === 'string'
}

Try / catch

try {
  store.delete(key)
} catch (err) {
  if (err instanceof TypeError && /expected key to be object/.test(err.message)) {
    log.warn('skipping cache delete: malformed key', key)
  } else {
    throw err
  }
}

Prevention

When it happens

Trigger: Calling memoryCacheStore.delete('http://x/y') with a string, a number, null, undefined, or a boolean instead of an object like { origin, method, path }. Reproduces in the cache-interceptor internals if a custom store wrapper forwards the wrong shape.

Common situations: Custom CacheStore implementations that pass the request URL string directly; migrating from a string-keyed cache; refactoring that drops the key object; tests that call delete() with a primitive for convenience.

Related errors


AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13). Data as JSON: /api/errors/4352c1db7ad50f15. Report an issue: GitHub.