BoundaryML/baml · error · RuntimeCallbackError

Failed to recv cred response across WASM bridge: {0}

Error message

Failed to recv cred response across WASM bridge: {0}

What it means

RuntimeCallbackError::RecvError is raised when the tokio broadcast `Receiver::recv` awaiting the credential response from the JS/WASM side fails at the transport level (not a credential error from JS itself, which comes back as Ok(Err(...))). This means the broadcast channel errored - typically closed or lagged - so no credential response was ever received.

Source

Thrown at engine/baml-runtime/src/types/js_callback_provider.rs:29

    #[serde(rename = "error")]
    Err(JsCallbackError),
}

#[derive(Debug, serde::Deserialize, Eq, PartialEq)]
/// Deserialization helper for js_callback_bridge; declared here to enable deserialization unit testing.
pub struct JsCallbackError {
    pub name: String,
    pub message: String,
}

#[derive(Debug, Error, Clone)]
/// For baml-src-reader and aws-cred-provider, provide a statically defined type which is Send + Sync
/// anyhow::Error is not Send + Sync, so it's convoluted to use it in this callback context
pub enum RuntimeCallbackError {
    #[error("Failed to send cred request across WASM bridge: {0}")]
    SendError(String),

    #[error("Failed to recv cred response across WASM bridge: {0}")]
    RecvError(String),

    #[error("Type error in JS callback: {0}")]
    JsCallbackTypeError(String),

    #[error("JS callback error: {name}: {message}")]
    JsCallbackRuntimeError { name: String, message: String },

    #[error("BAML internal error - credential provider bridges not initialized")]
    NoCredProviderBridge,
}

static_assertions::assert_impl_all!(RuntimeCallbackError: Send, Sync);

pub type RuntimeCallbackResult<T> = Result<T, RuntimeCallbackError>;

static JS_CALLBACK_PROVIDER_SINGLETON: OnceLock<JsCallbackProvider> = OnceLock::new();

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Retry the credential request; the provider clones/resubscribes the broadcast receiver on each call, so a fresh call often succeeds.
  2. Ensure the JS credential provider callback does not drop/replace the bridge channel while requests are in flight.
  3. Check for runtime shutdown or worker termination racing with the LLM call and serialize initialization before calls.
  4. If 'lagged' appears in the message, reduce concurrency of simultaneous cred requests or increase the broadcast channel capacity in the bridge setup.

Example fix

// before: tearing down the runtime while a call is in flight
runtime.dispose();
await b.GenerateSummary(input); // RecvError: channel closed

// after: await in-flight work before disposing
await b.GenerateSummary(input);
runtime.dispose();
Defensive patterns

Strategy: retry

Try / catch

// JS side: bounded retry for transient bridge recv failures
async function callWithRetry(fn, retries = 2) {
  for (let i = 0; i <= retries; i++) {
    try { return await fn(); }
    catch (e) {
      if (String(e).includes('Failed to recv cred response') && i < retries) continue;
      throw e;
    }
  }
}

Prevention

When it happens

Trigger: JsCallbackProvider::aws_req (js_callback_provider.rs:105-114) or gcp_req (js_callback_provider.rs:128-138) calls `resp_rx.recv().await` and gets `Err(e)` (e.g. `RecvError::Closed` after the sender was dropped, or `RecvError::Lagged` because the subscriber missed too many messages), which becomes `RuntimeCallbackError::RecvError(e.to_string())`.

Common situations: The JS side resolved/rejected the credential promise but the bridge sender was dropped before the response was published, the WASM runtime shut down mid-request, or many concurrent AWS cred requests caused a lagged broadcast receiver.

Related errors


AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12). Data as JSON: /api/errors/6fa55186b6a2ba7f. Report an issue: GitHub.