apache/beam · error

StateChannel[ ].Send( ): context canceled

Error message

StateChannel[%v].Send(%v): context canceled

What it means

StateChannel.Send waits for the response future; if the channel's DoneCh fires (the stream was closed) before a response arrives, Send returns this wrapped error carrying the underlying closedErr. The message says "context canceled" because the send effectively aborted — the stream ended without answering the request.

Solutions

  1. Look at the wrapped closedErr to find why the stream closed and fix that root cause.
  2. Verify the runner did not crash; restart the job if the runner died mid-bundle.
  3. Check idle/deadline timeouts on proxies between the harness and the state service.
  4. Retry the failing bundle; use runner retry policies to mask transient stream drops.
Defensive patterns

Strategy: retry

Try / catch

if err != nil && strings.Contains(err.Error(), "context canceled") {
    return retryable(err) // stream ended before response; let runner retry the bundle
}

Prevention

When it happens

Trigger: Sending a state request and, while blocked on the per-request response channel, the receive loop terminates (EOF, gRPC error, runner shutdown), closing DoneCh before the response is delivered.

Common situations: Runner terminating mid-bundle, state stream dropped by network interruption, harness shutdown racing outstanding state requests, gRPC server rejecting an in-flight request and tearing down the stream.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/703ecaf42d0ac3e2. Report an issue: GitHub.

Appendix: source

Thrown at sdks/go/pkg/beam/core/runtime/harness/statemgr.go:799

	ch := make(chan *fnpb.StateResponse, 1)
	c.mu.Lock()
	if c.closedErr != nil {
		defer c.mu.Unlock()
		return nil, errors.Wrapf(c.closedErr, "StateChannel[%v].Send(%v): channel closed due to: %v", c.id, id, c.closedErr)
	}
	c.responses[id] = ch
	c.mu.Unlock()

	c.requests <- req

	var resp *fnpb.StateResponse
	select {
	case resp = <-ch:
	case <-c.DoneCh:
		c.mu.Lock()
		defer c.mu.Unlock()
		return nil, errors.Wrapf(c.closedErr, "StateChannel[%v].Send(%v): context canceled", c.id, id)
	}
	if resp.Error != "" {
		return nil, errors.New(resp.Error)
	}
	return resp, nil
}

View on GitHub (pinned to 12126d8942)