vitest-dev/vitest · error · TypeError

[vitest] Mocks require a url string.

Error message

[vitest] Mocks require a url string.

What it means

Thrown as a `TypeError` by `MockerRegistry.register` (multi-argument overload) when the `url` argument is not a string. The `url` is the resolved module URL used as the registry key (and for browser-mode request matching); it must be a string so the mock can be stored and looked up by URL.

Solutions

  1. Verify the argument order matches the overload signature `(type, raw, id, url, factoryOrRedirect)`.
  2. Ensure the RPC `resolveMock`/`resolveId` response includes a string `resolvedUrl` and that it is forwarded as `url`.
  3. Add a defensive default (e.g., fall back to `id`) only if you understand why the URL is missing.

Example fix

// before — arguments swapped (url and id)
registry.register('automock', raw, url, id)
// after — correct order: type, raw, id, url
registry.register('automock', raw, id, url)
Defensive patterns

Strategy: validation

Validate before calling

// Validate url is a string before calling register.
function registerSafe(registry: MockerRegistry, type: any, raw: string, id: string, url: unknown, extra?: any) {
  if (typeof url !== 'string') {
    throw new TypeError('url must be a string')
  }
  return registry.register(type, raw, id, url, extra)
}

Type guard

function isUrlString(value: unknown): value is string {
  return typeof value === 'string'
}

Prevention

When it happens

Trigger: Calling `register(type, raw, id, url, ...)` with `url` set to `undefined` or a non-string — typically because the RPC resolution did not return a `resolvedUrl` or the caller passed arguments out of order (note the overload order is `type, raw, id, url`, not `type, raw, url, id`).

Common situations: Misordered positional arguments in a forked runner; an RPC response missing `resolvedUrl`; passing the URL field under a different name.

Related errors


AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11). Data as JSON: /api/errors/477cef446de0fb99. Report an issue: GitHub.

Appendix: source

Thrown at packages/mocker/src/registry.ts:99

      else if (event.type === 'redirect') {
        const module = RedirectedModule.fromJSON(event)
        this.add(module)
        return module
      }
      else if (event.type === 'manual') {
        throw new Error(`Cannot set serialized manual mock. Define a factory function manually with \`ManualMockedModule.fromJSON()\`.`)
      }
      else {
        throw new Error(`Unknown mock type: ${(event as any).type}`)
      }
    }

    if (typeof raw !== 'string') {
      throw new TypeError('[vitest] Mocks require a raw string.')
    }

    if (typeof url !== 'string') {
      throw new TypeError('[vitest] Mocks require a url string.')
    }

    if (typeof id !== 'string') {
      throw new TypeError('[vitest] Mocks require an id string.')
    }

    if (type === 'manual') {
      if (typeof factoryOrRedirect !== 'function') {
        throw new TypeError('[vitest] Manual mocks require a factory function.')
      }
      const mock = new ManualMockedModule(raw, id, url, factoryOrRedirect)
      this.add(mock)
      return mock
    }
    else if (type === 'automock' || type === 'autospy') {
      const mock = type === 'automock'
        ? new AutomockedModule(raw, id, url)
        : new AutospiedModule(raw, id, url)

View on GitHub (pinned to 1fa9837ec2)