windmill-labs/windmill · error · std::io::Error

e.to_string() (Bedrock stream receive error wrapped in io::E

Error message

e.to_string() (Bedrock stream receive error wrapped in io::Error, propagated to the AI streaming response)

What it means

In the Bedrock AI provider's SSE proxy (`sdk_stream_to_sse`), the stream of events from the AWS Bedrock SDK is converted into server-sent-event chunks. When the SDK's event stream returns an error mid-stream, the code wraps `e.to_string()` in a fresh `std::io::Error` (kind `Other`) and yields it downstream before breaking the loop. The original error type is lost — only its string survives — so consumers see a generic io error whose message is the underlying Bedrock error.

Source

Thrown at backend/windmill-ai/src/providers/bedrock.rs:474

    let created = std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)
        .unwrap()
        .as_secs();

    async_stream::stream! {
        let mut stream = stream;
        let mut state = BedrockSseStreamState::new(id, model, created);

        loop {
            match stream.recv().await {
                Ok(Some(event)) => {
                    for chunk in bedrock_sse_chunks_for_event(&event, &mut state) {
                        yield Ok(chunk);
                    }
                }
                Ok(None) => break,
                Err(e) => {
                    yield Err(std::io::Error::new(
                        std::io::ErrorKind::Other,
                        e.to_string(),
                    ));
                    break;
                }
            }
        }

        yield Ok(Bytes::from("data: [DONE]\n\n"));
    }
}

#[derive(Debug)]
struct BedrockSseStreamState {
    id: String,
    model: String,
    created: u64,
    tool_calls: HashMap<usize, (String, String, String)>,

View on GitHub (pinned to e474e8803c)

Solutions

  1. Inspect the wrapped message in the io error — it contains the real Bedrock error (throttle/access denied/etc.) and act on that cause
  2. Check IAM permissions for `bedrock:InvokeModelWithResponseStream` and model access grants in the region
  3. Add retry/backoff for throttling errors on the client side
  4. Verify AWS credentials/region configuration; refresh long-lived sessions
Defensive patterns

Strategy: retry

Validate before calling

// before streaming, verify credentials and model access
await bedrock.send(new InvokeModelCommand({ modelId, body: smallProbe }));

Try / catch

try {
  await streamAiResponse();
} catch (e) {
  const msg = String(e.cause ?? e);
  if (/ThrottlingException/i.test(msg)) await backoffRetry();
  else if (/AccessDenied/i.test(msg)) fixIamPermissions();
}

Prevention

When it happens

Trigger: The Bedrock runtime SDK's `receive_event` / stream returns `Err` while streaming a model response: throttling (TooManyRequests), model access denied, expired AWS credentials, stream timeouts, or the model endpoint aborting the stream mid-generation.

Common situations: Hitting Bedrock rate limits during bursts of AI requests, IAM policies missing `bedrock:InvokeModelWithResponseStream`, AWS credentials expiring during a long generation, region/model-id misconfiguration surfacing only mid-stream.

Related errors


AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03). Data as JSON: /api/errors/97aff747f49d7a73. Report an issue: GitHub.