{"record":{"id":"ab4c0a11038a0011","repo":"Tyrrrz/DiscordChatExporter","slug":"request-to-url-failed-forbidden","errorCode":null,"errorMessage":"Request to '{url}' failed: forbidden.","messagePattern":"Request to '(.+?)' failed: forbidden\\.","errorType":"exception","errorClass":"DiscordChatExporterException","httpStatus":403,"severity":"error","filePath":"DiscordChatExporter.Core/Discord/DiscordClient.cs","lineNumber":150,"sourceCode":"        );\n\n    private async ValueTask<JsonElement> GetJsonResponseAsync(\n        string url,\n        CancellationToken cancellationToken = default\n    )\n    {\n        using var response = await GetResponseAsync(url, cancellationToken);\n\n        if (!response.IsSuccessStatusCode)\n        {\n            throw response.StatusCode switch\n            {\n                HttpStatusCode.Unauthorized => throw new DiscordChatExporterException(\n                    \"Authentication token is invalid.\",\n                    true\n                ),\n\n                HttpStatusCode.Forbidden => throw new DiscordChatExporterException(\n                    $\"Request to '{url}' failed: forbidden.\"\n                ),\n\n                HttpStatusCode.NotFound => throw new DiscordChatExporterException(\n                    $\"Request to '{url}' failed: not found.\"\n                ),\n\n                _ => throw new DiscordChatExporterException(\n                    $\"\"\"\n                    Request to '{url}' failed: {response\n                        .StatusCode.ToString()\n                        .SeparateWords(' ')\n                        .ToLowerInvariant()}.\n                    Response content: {await response.Content.ReadAsStringAsync(\n                        cancellationToken\n                    )}\n                    \"\"\",\n                    true","sourceCodeStart":132,"sourceCodeEnd":168,"githubUrl":"https://github.com/Tyrrrz/DiscordChatExporter/blob/f6865c82167c3bfee4455da80a1f1ca5e71b95ad/DiscordChatExporter.Core/Discord/DiscordClient.cs#L132-L168","documentation":"Thrown as DiscordChatExporterException (non-fatal) from GetJsonResponseAsync when a request returns 403 Forbidden. The token is valid but the authenticated identity is not permitted to perform the operation or view the resource. The url is interpolated into the message to identify which endpoint was blocked.","triggerScenarios":"Any GetJsonResponseAsync call whose response status is HttpStatusCode.Forbidden. Common cases: requesting messages in a channel the bot cannot read, fetching a guild the user is not in, or an endpoint requiring elevated permissions the bot lacks.","commonSituations":"Bot added without Read Message History permission; bot lacks View Channel on a private channel; user token querying a guild they left; attempting to read DM channels the account does not have access to; privileged operations without the required OAuth scope.","solutions":["Grant the bot View Channel + Read Message History on the target channel/role.","Re-add the bot to the guild with correct permissions, or have an admin adjust role perms.","For user tokens, confirm the account is still a member of the guild/DM.","Filter the export list to only channels the identity can access."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Pre-check access by listing channels the identity can see\nvar channels = await discord.GetGuildChannelsAsync(guildId, ct);\nif (!channels.Any(c => c.Id == targetChannelId))\n    throw new UnauthorizedAccessException(\"Identity cannot see the target channel.\");","typeGuard":null,"tryCatchPattern":"try { await exporter.ExportChannelAsync(req, progress, ct); }\ncatch (DiscordChatExporterException ex) when (ex.Message.Contains(\"forbidden\"))\n{\n    logger.LogWarning(\"Skipping {Channel}: access forbidden\", req.Channel.Name);\n}","preventionTips":["Confirm the bot role has View Channel and Read Message History.","Filter batch lists to channels the identity can access.","Treat 403 as per-channel skip, not a hard abort."],"tags":["authorization","permissions","discord-api","http-403"],"backgroundTag":null,"analyzedSha":"f6865c82167c3bfee4455da80a1f1ca5e71b95ad","analyzedAt":"2026-08-13T18:08:46.403Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}