{"record":{"id":"51da153f65609c7e","repo":"stride3d/stride","slug":"crash-report-upload-timed-out","errorCode":null,"errorMessage":"Crash report upload timed out.","messagePattern":"Crash report upload timed out\\.","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"warning","filePath":"sources/crashreport/Stride.CrashReport/CrashReportSender.cs","lineNumber":211,"sourceCode":"                if (response.IsSuccessStatusCode)\n                    Interlocked.Increment(ref succeeded);\n                else\n                    failure ??= $\"HTTP {(int)response.StatusCode} {response.ReasonPhrase}\";\n                return response;\n            }\n            catch (Exception exception)\n            {\n                failure ??= exception.Message;\n                throw;\n            }\n        }\n\n        public void ThrowIfNothingLanded()\n        {\n            if (failure != null)\n                throw new IOException(\"Crash report upload failed: \" + failure);\n            if (succeeded == 0)\n                throw new IOException(\"Crash report upload timed out.\");\n        }\n    }\n\n    /// <summary>\n    /// Maps report entries onto Sentry structures: searchable tags, GPU/memory contexts, log lines and\n    /// undo/redo actions as breadcrumbs, everything else as extra data. The full report text stays\n    /// attached as report.txt, which is exactly what the window's View report shows.\n    /// </summary>\n    private static void MapReport(Scope scope, CrashReportData report)\n    {\n        var gpus = new Dictionary<string, Dictionary<string, string>>();\n        var memory = new Dictionary<string, string>();\n        string activeAdapter = null;\n\n        foreach (var (key, value) in report.Data)\n        {\n            switch (key)\n            {","sourceCodeStart":193,"sourceCodeEnd":229,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/crashreport/Stride.CrashReport/CrashReportSender.cs#L193-L229","documentation":"If the crash-report upload finished with zero successful landings and no recorded exception, ThrowIfNothingLanded reports it as a timeout: no part of the report reached the server within the allowed time.","triggerScenarios":"SendCoreAsync completes but succeeded == 0 and failure == null — all upload attempts neither failed explicitly nor landed, typically because requests exceeded the timeout window or were abandoned.","commonSituations":"Very slow or partially blocked networks; firewall silently dropping packets instead of refusing; an unreachable Sentry endpoint where connections hang rather than error.","solutions":["Retry the upload (or leave the run directory for a later session's retry)","Check network/proxy configuration for silently dropping firewalls","Increase the upload timeout budget if the environment is slow, or send reports asynchronously at next startup"],"exampleFix":"// before\nawait sender.SendAsync(report); // blocks shutdown on slow network\n// after\ntry { await sender.SendAsync(report); }\ncatch (IOException e) when (e.Message.Contains(\"timed out\")) { /* defer to next launch */ }","handlingStrategy":"retry","validationCode":"// pre-check endpoint reachability before attempting upload\nusing var ping = new HttpClient { Timeout = TimeSpan.FromSeconds(5) };\nvar reachable = await ping.GetAsync(dsnEndpoint) is { } resp;","typeGuard":null,"tryCatchPattern":"try { await sender.SendAsync(report); }\ncatch (IOException e) when (e.Message.Contains(\"timed out\"))\n{ /* schedule retry at next startup */ }","preventionTips":["Defer uploads off the critical crash path","Retry pending run directories at next launch","Monitor/verify the report endpoint is not silently blocked by firewalls"],"tags":["network","timeout","crash-reporting"],"backgroundTag":"request-timeout","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}