{"record":{"id":"f84ca15202a28686","repo":"microsoft/aspire","slug":"dashboard-api-returned-unexpected-content-type-0-expected","errorCode":null,"errorMessage":"Dashboard API returned unexpected content type '{0}'. Expected JSON response.","messagePattern":"Dashboard API returned unexpected content type '(.+?)'\\. Expected JSON response\\.","errorType":"http","errorClass":"HttpRequestException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Cli/Commands/TelemetryCommandHelpers.cs","lineNumber":166,"sourceCode":"    /// </exception>\n    public static void EnsureTelemetryApiResponse(HttpResponseMessage response)\n    {\n        // A 200 with text/html content type indicates the Blazor fallback route handled the request,\n        // meaning the telemetry API endpoint doesn't exist. Treat this the same as a 404.\n        if (response.IsSuccessStatusCode &&\n            response.Content.Headers.ContentType?.MediaType is \"text/html\")\n        {\n            throw new HttpRequestException(\n                HttpRequestError.InvalidResponse,\n                statusCode: HttpStatusCode.NotFound);\n        }\n\n        response.EnsureSuccessStatusCode();\n\n        if (!HasJsonContentType(response))\n        {\n            var mediaType = response.Content.Headers.ContentType?.MediaType ?? \"(none)\";\n            throw new HttpRequestException(\n                HttpRequestError.InvalidResponse,\n                string.Format(CultureInfo.InvariantCulture, TelemetryCommandStrings.UnexpectedContentType, mediaType),\n                inner: null,\n                response.StatusCode);\n        }\n    }\n\n    /// <summary>\n    /// Resolves an AppHost connection and gets Dashboard API info.\n    /// </summary>\n    /// <param name=\"connectionResolver\">The connection resolver for AppHost discovery.</param>\n    /// <param name=\"interactionService\">The interaction service for displaying messages.</param>\n    /// <param name=\"httpClientFactory\">The HTTP client factory for making API calls.</param>\n    /// <param name=\"logger\">The logger for diagnostic messages.</param>\n    /// <param name=\"projectFile\">The optional AppHost project file.</param>\n    /// <param name=\"dashboardUrl\">The optional direct dashboard URL (mutually exclusive with <paramref name=\"projectFile\"/>).</param>\n    /// <param name=\"apiKey\">The optional API key for dashboard authentication.</param>\n    /// <param name=\"requireDashboard\">","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Cli/Commands/TelemetryCommandHelpers.cs#L148-L184","documentation":"TelemetryCommandHelpers.EnsureTelemetryApiResponse validates that the Dashboard API's HTTP response is both successful and JSON-typed before deserialization. When the response content type is not JSON, it throws HttpRequestException (HttpRequestError.InvalidResponse) formatted with the actual media type, guarding downstream JSON parsing from garbage.","triggerScenarios":"Calling telemetry/resource list commands (e.g. GetAllResourcesAsync) against a dashboard endpoint that returns HTML (error page, auth redirect), plain text, or an empty body with no content type.","commonSituations":"Wrong dashboard URL/port configured (ASPIRE_DASHBOARD_* env vars); dashboard behind a proxy or auth page returning HTML; dashboard version serving a different endpoint shape; hitting a plain HTTP server instead of the dashboard API.","solutions":["Verify the dashboard API URL/port points at the actual Aspire dashboard (check ASPIRE_DASHBOARD_ env vars and the printed dashboard URL)","Check for proxies/auth redirects returning HTML and bypass or authenticate them","Ensure the dashboard is running a version compatible with the CLI's telemetry API","Catch HttpRequestException and inspect the message for the actual media type received"],"exampleFix":"// before\nvar url = \"http://localhost:18888\"; // some other service\n// after\nvar url = Environment.GetEnvironmentVariable(\"ASPIRE_DASHBOARD_URL\") ?? \"http://localhost:18888\";","handlingStrategy":"try-catch","validationCode":"if (!response.IsSuccessStatusCode ||\n    !response.Content.Headers.ContentType?.MediaType!.Contains(\"json\")!) { /* bail before parsing */ }","typeGuard":"static bool IsJsonResponse(HttpResponseMessage r) =>\n    r.Content.Headers.ContentType?.MediaType is string mt &&\n    (mt.Contains(\"json\") || mt.EndsWith(\"+json\"));","tryCatchPattern":"try { await telemetry.GetAllResourcesAsync(ct); }\ncatch (HttpRequestException ex) when (ex.Message.Contains(\"content type\"))\n{ Console.Error.WriteLine(\"Dashboard returned non-JSON; check the dashboard URL/port.\"); }","preventionTips":["Verify the dashboard URL/port before calling the API","Confirm you're talking to the Aspire dashboard, not a proxy or another service","Check dashboard and CLI version compatibility","Handle auth/login flows so HTML error pages aren't returned"],"tags":["http","telemetry","dashboard","content-type"],"backgroundTag":"unexpected-response-shape","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}