InvalidOperationException: An invalid request URI was provided. Either the request URI must be an absolute URI or BaseAddress must be set.
means the HttpClient was handed a relative path such as "api/v1/patients"
while its BaseAddress was empty. Set BaseAddress on the client, or pass
a full URL that starts with http:// or https://.
When you set BaseAddress, end it with a slash and write the relative path without
a leading slash. In the test below that was the one combination of the four that reached
the endpoint; the other three answered 404.
The error
PS ...\Cli> dotnet run --no-build
Unhandled exception. System.InvalidOperationException: An invalid request URI was provided. Either the request URI must be an absolute URI or BaseAddress must be set.
at System.Net.Http.HttpClient.PrepareRequestMessage(HttpRequestMessage request)
at System.Net.Http.HttpClient.GetStringAsync(Uri requestUri, CancellationToken cancellationToken)
at Program.<Main>$(String[] args) in ...\Cli\Program.cs:line 6
at Program.<Main>(String[] args)
The code that threw:
using var http = new HttpClient();
var text = await http.GetStringAsync("api/v1/patients");
Why it happens
The string "api/v1/patients" has no scheme and no host, so it is a relative
URI. The client has nothing to resolve it against because BaseAddress was
never set. The stack trace shows where it stopped: in
HttpClient.PrepareRequestMessage, the step that builds the request before it
is sent. The fix is in your code, not on the server.
The fix
using var http = new HttpClient { BaseAddress = new Uri("http://127.0.0.1:15801/api/v1/") };
var text = await http.GetStringAsync("patients");
Console.WriteLine(text);
PS ...\Cli> dotnet run --no-build -- fixed
200 from /api/v1/patients: Maria Garcia, David Chen
The slashes matter. The same client was run against the test server with each
combination of a trailing slash on BaseAddress and a leading slash on the path,
printing the URI that was actually requested:
PS ...\Cli> dotnet run --no-build -- combos
BaseAddress=http://127.0.0.1:15801/api/v1/ path=patients -> http://127.0.0.1:15801/api/v1/patients 200
BaseAddress=http://127.0.0.1:15801/api/v1/ path=/patients -> http://127.0.0.1:15801/patients 404
BaseAddress=http://127.0.0.1:15801/api/v1 path=patients -> http://127.0.0.1:15801/api/patients 404
BaseAddress=http://127.0.0.1:15801/api/v1 path=/patients -> http://127.0.0.1:15801/patients 404
A leading slash on the path replaced the whole /api/v1 part, and a base without
a trailing slash lost its last segment (v1). Only the trailing-slash base with
a slash-free path kept /api/v1/. Printing
response.RequestMessage.RequestUri, as the test does, shows which URL a 404
really went to.
How it was reproduced
A console app (dotnet new console, no packages) on .NET SDK 10.0.403 called
GetStringAsync("api/v1/patients") on a new HttpClient. The slash
test ran against a minimal API (dotnet new web) started on
http://127.0.0.1:15801 with one route, /api/v1/patients, and a
fallback that answers 404 with the requested path, so every wrong combination showed up
as a 404 and the printed request URI said where it had gone.
Frequently asked
- How do I fix 'An invalid request URI was provided' in HttpClient?
- Set BaseAddress on the HttpClient (or on the named client in AddHttpClient) and keep passing the relative path, or pass an absolute URL that starts with http:// or https://.
- Should HttpClient BaseAddress end with a slash?
- Yes for a base with a path. In the test, http://127.0.0.1:15801/api/v1 plus patients requested /api/patients and got 404, while the same base with a trailing slash requested /api/v1/patients and got 200.
- Why does a leading slash in the path ignore my BaseAddress path?
- A path that starts with a slash is resolved from the root of the host. In the test, /patients against a base of /api/v1/ requested http://127.0.0.1:15801/patients.
More decoded errors in the Fixes category. If the client now reaches the address but nothing listens there, see No connection could be made because the target machine actively refused it.