grpc/grpc-go · error

failed to create a stream to external processor: %v

Error message

failed to create a stream to external processor: %v

What it means

Raised during NewStream when i.procClient.Process(procCtx) returns an error — the channel exists but the bidirectional stream to the external processor could not be opened. This is an RPC-level (not dial-level) failure against the ext-proc server and is funneled through handleInitError, which honors failure_mode_allow.

Source

Thrown at internal/xds/httpfilter/extproc/ext_proc.go:320

		config:                 i.config,
		metricsRecorder:        i.metricsRecorder,
		target:                 i.target,
		clientHeadersStartTime: timeNow(),
		// Construct request attributes once during stream initialization to capture
		// the original, unmutated request metadata and RPC info. For streaming
		// RPCs, where stream creation and message transmission are separable,
		// initializing attributes upfront avoids repeated protobuf construction on
		// subsequent SendMsg and RecvMsg calls.
		reqAttrs: constructRequestAttributes(ri, outgoingMD, added, i.config.requestAttributes),
	}

	// In the ClientStream API, outgoing headers are sent immediately when the
	// stream is created. Because we need to send or mutate these headers before
	// they go over the wire, we must establish the ext_proc stream now rather
	// than deferring it.
	var err error
	if csCommon.procStream, err = i.procClient.Process(procCtx); err != nil {
		return csCommon.handleInitError(fmt.Errorf("failed to create a stream to external processor: %v", err), newStream, opts...)
	}

	// Observability mode.
	if i.config.observabilityMode {
		ocs := &observabilityClientStream{
			commonStream: csCommon,
			procRecvDone: make(chan struct{}),
		}

		// If the request header processing mode is set to "Send", forward the
		// headers to the external processor server.
		if i.config.processingModes.requestHeaderMode == modeSend {
			if err = ocs.sendToProcessor(ocs.requestHeaders(outgoingMD, added)); err != nil {
				return ocs.handleInitError(fmt.Errorf("failed to send client headers to external processor server: %v", err), newStream, opts...)
			}
		}

		// Defer the closing of ext proc stream by the defined defferred close

View on GitHub (pinned to 03255a9237)

Solutions

  1. Inspect the wrapped error (%v) for the gRPC status code — UNAVAILABLE points to transport, PERMISSION_DENIED to authz.
  2. If transient, rely on the channel reconnecting and retry the RPC; consider raising grpc_service.timeout if the deadline is firing.
  3. Set failure_mode_allow: true so handleInitError bypasses the processor and falls through to the dataplane stream instead of failing the RPC.
  4. Verify server-side logs for why the Process stream was rejected.

Example fix

// before: any stream-open failure kills the RPC
failure_mode_allow: false

// after: tolerate ext-proc stream-open failures by bypassing
failure_mode_allow: true
Defensive patterns

Strategy: fallback

Try / catch

// Stream-open errors honor failure_mode_allow via handleInitError.
// Set failure_mode_allow:true so the user RPC falls through to the dataplane
// instead of failing with codes.Internal.

Prevention

When it happens

Trigger: Process() RPC initiation fails: server returns UNAVAILABLE/PERMISSION_DENIED, transport closed mid-handshake, server-side stream limit hit, deadline exceeded on procCtx (server.Timeout), or context canceled before the stream was established.

Common situations: Ext-proc server up but rejecting streams (authz, mTLS). grpc_service.timeout too short so procCtx deadline fires at stream open. Server overloaded / refusing new streams. Transient network blip after channel became idle.

Related errors


AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07). Data as JSON: /api/errors/4d4f323c97ddbb64. Report an issue: GitHub.