iOfficeAI/OfficeCLI · error · InvalidOperationException

render timed out after 120s

Error message

render timed out after 120s

What it means

Thrown by WatchServer's render path when the child `view <file> html` process does not exit within 120 seconds. A linked CancellationTokenSource cancels after 120s; on OperationCanceledException the process tree is killed and this InvalidOperationException is thrown, which the caller wraps into a 500 response. It bounds watch latency so a wedged render cannot stall the server.

Source

Thrown at src/officecli/Core/Watch/WatchServer.cs:2687

                string renderErr = "";
                int exitCode = -1;
                using (var proc = System.Diagnostics.Process.Start(psi))
                {
                    if (proc != null)
                    {
                        using var renderCts = CancellationTokenSource.CreateLinkedTokenSource(token);
                        renderCts.CancelAfter(TimeSpan.FromSeconds(120));
                        var drainErr = proc.StandardError.ReadToEndAsync(renderCts.Token);
                        var drainOut = proc.StandardOutput.ReadToEndAsync(renderCts.Token);
                        try
                        {
                            await proc.WaitForExitAsync(renderCts.Token);
                        }
                        catch (OperationCanceledException)
                        {
                            try { proc.Kill(entireProcessTree: true); } catch { }
                            throw new InvalidOperationException("render timed out after 120s");
                        }
                        renderErr = await drainErr;
                        _ = await drainOut;
                        exitCode = proc.ExitCode;
                    }
                }
                if (exitCode != 0 || !File.Exists(tmpOut))
                {
                    var reason = string.IsNullOrWhiteSpace(renderErr) ? $"render exited {exitCode}" : renderErr.Trim();
                    throw new InvalidOperationException(reason);
                }
                html = await File.ReadAllTextAsync(tmpOut, token);
            }
            catch (Exception ex) when (ex is not OperationCanceledException)
            {
                var sb500 = new StringBuilder("{\"error\":");
                AppendJsonString(sb500, $"failed to render {Path.GetFileName(newPath)}: {ex.Message}");
                sb500.Append('}');

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Render a smaller or simpler document.
  2. Retry once; transient load can cause a one-off overrun.
  3. Check the renderer is not blocked on a network/font fetch.
Defensive patterns

Strategy: retry

Validate before calling

// No pre-check; mitigate by keeping documents renderable in well under 120s.
// If you control the source, split very large decks into smaller files.

Try / catch

// The watch server already returns HTTP 500 with {"error":"...timed out..."}.
// Client: retry the view/refresh once; if it persists, reduce document size.

Prevention

When it happens

Trigger: The document being rendered is very large/complex and the renderer exceeds 120s; the renderer process hung/deadlocked; the system is heavily loaded.

Common situations: Huge presentations/documents; a renderer with a pending font/asset fetch blocking it; resource-constrained host.

Understand the failure class

Related errors


AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13). Data as JSON: /api/errors/b7bf82e5ae3b597b. Report an issue: GitHub.