amir20/dozzle · info

canceled: with

Error message

canceled: %v with %w

What it means

rpcErrToErr maps gRPC status code Canceled to "canceled: %v with %w", wrapping context.Canceled so callers can use errors.Is(err, context.Canceled). It indicates the RPC was cancelled, typically by the caller's own context or a client disconnect, not a server failure.

Solutions

  1. Check errors.Is(err, context.Canceled) and log at debug level; it is usually expected during shutdown/navigation
  2. If cancellations are unexpected, audit who cancels the parent ctx (http request lifecycle, timeout wrappers)
  3. Do not reconnect on Canceled; only resubscribe on genuine stream failures
  4. Increase per-request deadlines if intentional timeouts are cutting streams short

Example fix

// before
if err := <-streamErr; err != nil { log.Error().Err(err).Msg("stream error") }
// after
if err := <-streamErr; err != nil {
    if errors.Is(err, context.Canceled) { return } // expected on disconnect
    log.Error().Err(err).Msg("stream error")
}
Defensive patterns

Strategy: try-catch

Try / catch

if err != nil && errors.Is(err, context.Canceled) {
    return // expected on client disconnect or shutdown; do not log as error
}

Prevention

When it happens

Trigger: Streaming calls (StreamEvents, StreamStats, sendLogs, etc.) whose ctx is cancelled: page navigation closing the SSE stream, client-side timeout, or explicit context cancel/shutdown.

Common situations: User closes a browser tab, cancelling the SSE request context; server shutdown cancelling all in-flight streams; a wrapped HTTP handler timing out and cancelling the request context.

Related errors


AI-assisted analysis of amir20/dozzle@d9463cbe21 (2026-09-07). Data as JSON: /api/errors/ee0d3a94e931011a. Report an issue: GitHub.

Appendix: source

Thrown at internal/agent/client.go:123

}

func rpcErrToErr(err error) error {
	if err == nil {
		return nil
	}

	status, ok := status.FromError(err)
	if !ok {
		return err
	}

	if status.Code() == codes.Unknown && status.Message() == "EOF" {
		return fmt.Errorf("EOF error while converting gRPC to error: %w", io.EOF)
	}

	switch status.Code() {
	case codes.Canceled:
		return fmt.Errorf("canceled: %v with %w", status.Message(), context.Canceled)
	case codes.DeadlineExceeded:
		return fmt.Errorf("deadline exceeded: %v with %w", status.Message(), context.DeadlineExceeded)
	case codes.Unknown:
		return fmt.Errorf("unknown error: %v with %w", status.Message(), err)
	case codes.OK:
		return nil
	default:
		return fmt.Errorf("unknown code: %v with %w", status.Code(), err)
	}
}

func (c *Client) LogsBetweenDates(ctx context.Context, containerID string, since time.Time, until time.Time, std container.StdType) (<-chan *container.LogEvent, error) {
	stream, err := c.client.LogsBetweenDates(ctx, &pb.LogsBetweenDatesRequest{
		ContainerId: containerID,
		Since:       timestamppb.New(since),
		Until:       timestamppb.New(until),
		StreamTypes: int32(std),
	})

View on GitHub (pinned to d9463cbe21)