dotnet/aspnetcore · error · Error
Invalid authentication refresh response received: expected J
Error message
Invalid authentication refresh response received: expected JSON content.
What it means
Thrown at HttpConnection.ts:440 when the refresh endpoint returned HTTP 200 but `response.content` is not a string, so it cannot be JSON.parse'd. The refresh handler expects a textual JSON body; a non-string body (e.g. an ArrayBuffer when the client was configured for binary, or an empty body) is unusable.
Source
Thrown at src/SignalR/clients/ts/signalr/src/HttpConnection.ts:440
const refreshUrl = this._createRefreshUrl(this._connectionUrl, this._connectionToken);
this._logger.log(LogLevel.Debug, `Sending authentication refresh request: ${refreshUrl}.`);
const request: HttpRequest = {
content: "",
headers: { ...headers, ...this._options.headers },
timeout: this._options.timeout,
withCredentials: this._options.withCredentials,
};
this._httpClient.markAuthenticationRefreshRequest(request);
const response = await this._httpClient.post(refreshUrl, request);
if (response.statusCode !== 200) {
throw new Error(`Unexpected status code returned from authentication refresh '${response.statusCode}'`);
}
if (typeof response.content !== "string") {
throw new Error("Invalid authentication refresh response received: expected JSON content.");
}
if (connectionGeneration !== this._connectionGeneration) {
return undefined;
}
const refreshResponse = JSON.parse(response.content) as { accessToken?: unknown, tokenLifetimeSeconds?: unknown };
if (typeof refreshResponse.accessToken === "string" && refreshResponse.accessToken) {
// Redirecting servers can return a transport token that should replace the current cached token.
this._setTransportAccessToken(refreshResponse.accessToken);
} else if (!this._transportAccessTokenFromServer) {
// Without a server-provided transport token, reuse the app token that successfully authenticated refresh.
const refreshRequestToken = this._httpClient.getRefreshRequestToken(response);
if (refreshRequestToken) {
this._httpClient.updateCachedToken(refreshRequestToken);
}
}
View on GitHub (pinned to 294cab2f9b)
Solutions
- Ensure the server returns a JSON string body for the refresh endpoint with Content-Type application/json.
- If you supply a custom httpClient in options, make sure HttpResponse.content is a string for text responses.
- Verify no middleware is converting the response to ArrayBuffer before the client parses it.
Example fix
// custom httpClient must return string content for refresh
// before
return { statusCode: 200, content: new ArrayBuffer(...) };
// after
return { statusCode: 200, content: JSON.stringify({ accessToken, tokenLifetimeSeconds }) }; Defensive patterns
Strategy: validation
Validate before calling
// if you use a custom httpClient, ensure refresh responses come back as strings
function assertStringContent(response) {
if (typeof response.content !== 'string') {
response.content = new TextDecoder().decode(response.content);
}
return response;
} Type guard
function isStringContent(res: { content: unknown }): res is { content: string } {
return typeof res.content === 'string';
} Try / catch
try { await hub.refreshAuthentication(); }
catch (e) {
if (/expected JSON content/.test(String(e))) {
// server or custom httpClient returned non-string - fix the httpClient, don't retry blindly
throw new Error('refresh response was not a JSON string; fix server content-type or httpClient');
}
throw e;
} Prevention
- If you pass options.httpClient, ensure HttpResponse.content is a string for JSON responses.
- Server should return Content-Type: application/json with a textual body.
- Avoid interceptors that convert response bodies to ArrayBuffer.
When it happens
Trigger: A custom HttpClient that resolves responses with content as ArrayBuffer or non-string types; a server returning a binary/empty body for the refresh endpoint; a response transformer that strips the string content. The literal check `typeof response.content !== "string"` fails.
Common situations: Wrapping or replacing the DefaultHttpClient with one that returns binary content; server middleware that compresses or alters content type without preserving the body; an interceptor that returns `{ content: null }` on certain paths.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Cannot refresh authentication before the connection is start
- Unexpected status code returned from authentication refresh
- Cannot refresh authentication when the connection is not act
- Authentication refresh is only supported with HTTP-based con
- Authentication refreshBeforeExpirationInMilliseconds must be
AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06).
Data as JSON: /api/errors/084c5b580872e23e.
Report an issue: GitHub.