dbt-labs/dbt-core · error

Failed to downcast response

Error message

Failed to downcast response

What it means

This `TryFrom<Value>` conversion for `AdapterResponse` succeeds only if the value is an `AdapterResponse` object or a plain string (treated as the response message). Any other minijinja Value falls through to this CannotDeserialize error, meaning the value could not be downcast to an adapter response.

Solutions

  1. Return an `AdapterResponse` object from the adapter callback, or a plain string message.
  2. If you control the caller, inspect the value's actual type (log its kind) and normalize it before conversion.
  3. Check for adapter/plugin version mismatches that changed the response object type expected by this conversion.

Example fix

// before
Ok(Value::from_object(serde_json::json!({"message": "OK"})))
// after
Ok(Value::from_object(AdapterResponse::new().with_message("OK")))
Defensive patterns

Strategy: type-guard

Validate before calling

// Rust
fn is_adapter_response(v: &Value) -> bool {
    v.downcast_object::<AdapterResponse>().is_some() || v.as_str().is_some()
}

Type guard

fn as_adapter_response(v: Value) -> Option<AdapterResponse> {
    v.downcast_object::<AdapterResponse>().map(|o| (*o).clone())
        .or_else(|| v.as_str().map(|m| AdapterResponse::new().with_message(m.to_string())))
}

Try / catch

match AdapterResponse::try_from(value) {
    Ok(resp) => ..., 
    Err(e) => log::warn!("response not downcastable: {e}"),
}

Prevention

When it happens

Trigger: Converting a Jinja `Value` into `AdapterResponse` where the value is neither an AdapterResponse object nor a string — e.g. a dict returned by a custom adapter callback, a number, or a serialized response map.

Common situations: Custom adapter/materialization code returning a dict or non-standard response from an `execute`/statement callback; plugin code that wraps the response in another object type after an adapter upgrade.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07). Data as JSON: /api/errors/12a8a3604f7e0886. Report an issue: GitHub.

Appendix: source

Thrown at crates/dbt-adapter/src/response.rs:370

            let is_known = key.as_str().is_some_and(|s| KNOWN_KEYS.contains(&s));
            if !is_known {
                keys.push(key.clone());
            }
        }
        Enumerator::Iter(Box::new(keys.into_iter()))
    }
}

impl TryFrom<Value> for AdapterResponse {
    type Error = minijinja::Error;

    fn try_from(value: Value) -> Result<Self, Self::Error> {
        if let Some(response) = value.downcast_object::<AdapterResponse>() {
            Ok((*response).clone())
        } else if let Some(message_str) = value.as_str() {
            Ok(AdapterResponse::new().with_message(message_str))
        } else {
            Err(minijinja::Error::new(
                minijinja::ErrorKind::CannotDeserialize,
                "Failed to downcast response",
            ))
        }
    }
}

/// load_result response object
#[derive(Debug)]
pub struct ResultObject {
    pub response: AdapterResponse,
    pub table: Option<AgateTable>,
    #[allow(unused)]
    pub data: Option<Value>,
}

impl ResultObject {
    pub fn new(response: AdapterResponse, table: Option<AgateTable>) -> Self {

View on GitHub (pinned to 0267ce9170)