Devolutions/UniGetUI · warning · InvalidOperationException

Timed out while waiting for operation {operationId}.

Error message

Timed out while waiting for operation {operationId}.

What it means

Thrown inside IpcClient.WaitForOperationAsync when the polling deadline (DateTime.UtcNow >= deadline) is reached before the operation reaches a terminal status (succeeded/failed/canceled). The deadline is startTime + Clamp(timeoutSeconds,1,3600), checked once per loop iteration after each poll.

Source

Thrown at src/UniGetUI.Interface.IpcApi/IpcClient.cs:186

        DateTime deadline = DateTime.UtcNow.AddSeconds(timeoutSeconds);
        while (true)
        {
            var operation = await GetOperationAsync(operationId)
                ?? throw new InvalidOperationException(
                    $"No tracked operation with id \"{operationId}\" was found."
                );

            if (
                operation.Status is "succeeded" or "failed" or "canceled"
            )
            {
                return operation;
            }

            if (DateTime.UtcNow >= deadline)
            {
                throw new InvalidOperationException(
                    $"Timed out while waiting for operation {operationId}."
                );
            }

            await Task.Delay(delayMilliseconds);
        }
    }

    public async Task<IpcCommandResult> CancelOperationAsync(string operationId)
    {
        return await ReadAuthenticatedJsonAsync<IpcCommandResult>(
                HttpMethod.Post,
                IpcHttpRoutes.Path($"/operations/{Uri.EscapeDataString(operationId)}/cancel")
            )
            ?? new IpcCommandResult
            {
                Status = "error",
                Command = "cancel-operation",

View on GitHub (pinned to 9b1d7d0eab)

Solutions

  1. Increase timeoutSeconds (up to the 3600 clamp) when calling WaitForOperationAsync for long operations.
  2. Call CancelOperationAsync then resubmit if the operation is genuinely hung.
  3. Check the operation output endpoint for clues about what it is blocked on.
  4. Lower delayMilliseconds to poll more frequently and react sooner to completion.

Example fix

// before
var result = await client.WaitForOperationAsync(id); // 300s default
// after
var result = await client.WaitForOperationAsync(id, timeoutSeconds: 1800);
Defensive patterns

Strategy: retry

Validate before calling

// Choose timeout based on expected operation cost:
int timeout = operationKind switch
{
    "install" or "uninstall" => 1800, // long-running
    _ => 300,
};

Try / catch

try { await client.WaitForOperationAsync(id, timeoutSeconds: 1800); }
catch (InvalidOperationException ex) when (ex.Message.Contains("Timed out"))
{ /* inspect output, cancel if hung, or retry with a longer timeout */ }

Prevention

When it happens

Trigger: An operation that runs longer than the supplied timeoutSeconds (default 300). A long package install/uninstall on a slow manager, a hung elevated process, or an operation stuck in a non-terminal status. Also if delayMilliseconds is large relative to timeout so few polls occur.

Common situations: Large bundle installs exceeding the 5-minute default. Network-bound managers (pip, npm) slow on cold cache. An operation whose manager process is awaiting interactive input and never returns. Defaulting to the 300s timeout for genuinely long tasks.

Understand the failure class

Related errors


AI-assisted analysis of Devolutions/UniGetUI@9b1d7d0eab (2026-08-13). Data as JSON: /api/errors/c95434c115ddc5cf. Report an issue: GitHub.