reactiveui/refit · error · InvalidOperationException

No stubbed route matched the request: {request.Method} {requ

Error message

No stubbed route matched the request: {request.Method} {request.RequestUri}

What it means

Thrown by StubHttp during SendAsync when an outgoing request matches none of the registered stubbed routes (checked across one-shot, reusable, and fallback tiers). The stub is a strict matcher — every request must be expected — so an unregistered request is treated as a test failure rather than a live call.

Source

Thrown at src/Refit.Testing/StubHttp.cs:347

        // for typed inspection even after the client disposes the request.
        await BufferRequestAsync(request, requestIndex).ConfigureAwait(false);

        // Priority tiers, tried in order regardless of declaration order: one-shot expectations, then reusable
        // background stubs, then catch-all fallbacks.
        var index = await FindMatchAsync(request, RouteTier.OneShot, cancellationToken).ConfigureAwait(false);
        if (index < 0)
        {
            index = await FindMatchAsync(request, RouteTier.Reusable, cancellationToken).ConfigureAwait(false);
        }

        if (index < 0)
        {
            index = await FindMatchAsync(request, RouteTier.Fallback, cancellationToken).ConfigureAwait(false);
        }

        if (index < 0)
        {
            throw new InvalidOperationException(
                $"No stubbed route matched the request: {request.Method} {request.RequestUri}");
        }

        if (!_routes[index].Reusable && !_routes[index].Fallback)
        {
            Consume(index);
        }

        var faulted = await ApplyBehaviorAsync(request, cancellationToken).ConfigureAwait(false);
        if (faulted is not null)
        {
            return faulted;
        }

        var response = await BuildResponseAsync(_responses[index], request).ConfigureAwait(false);

        // Honor cancellation requested during matching or by a responder (e.g. a test that cancels mid-send).
        cancellationToken.ThrowIfCancellationRequested();

View on GitHub (pinned to b455f65ecc)

Solutions

  1. Register a matching route: stub.Expect(HttpMethod.Post, "api/items") (use a fallback or reusable route if the exact URI varies).
  2. Compare the actual request in the error message to the registered templates and align method/path.
  3. If the call is incidental to the test, register a reusable/fallback route to absorb it rather than letting it fail matching.

Example fix

// before — request made but no route registered
await client.PostAsync(payload);

// after
stub.Expect(HttpMethod.Post, "api/items").WithBody(payload).Respond(200);
await client.PostAsync(payload);
Defensive patterns

Strategy: validation

Validate before calling

// Register a fallback so unexpected calls surface clearly instead of mismatching,
// or assert the call will match a registered route beforehand.
if (stub.Requests.Count == 0)
{
    Assert.Fail("No request was sent through the stub.");
}
// Optionally: stub.ExpectAny() / a fallback route to absorb incidental calls.

Try / catch

// Inspect the failure message for the actual method/URI, then register the matching route.
// The exception already prints: No stubbed route matched the request: POST http://.../api/x
stub.Expect(HttpMethod.Post, "api/x").Respond(200);

Prevention

When it happens

Trigger: The code under test issues a request (method or URI) that was not set up with stub.Expect(...)/Route(...), or whose URL differs (query string, trailing slash, casing in path, base address). FindMatchAsync returns -1 for all tiers and the guard fires.

Common situations: Mismatched HTTP method (expected POST, got PUT); URL template/path differences; query parameters not accounted for; forgot to register a route for a secondary call the SUT makes (e.g. token refresh, retries); base address/relative path mismatch changing the RequestUri.

Related errors


AI-assisted analysis of reactiveui/refit@b455f65ecc (2026-08-13). Data as JSON: /api/errors/d0614122ba82008f. Report an issue: GitHub.