unicity-aos/aos-ce · warning

Failed to parse from prompt builder

Error message

Failed to parse {label} from prompt builder: {e}

What it means

capsule-react parses items returned by the prompt builder into typed values T. When an individual array element fails serde_json::from_value, this warning is logged with the label (e.g., the item kind) and the element is skipped via filter_map — parsing continues for remaining items rather than failing the whole collection.

Solutions

  1. Inspect the {e} message and the offending array element's fields; fix the prompt builder output or the T struct to match.
  2. Add serde defaults/Option fields to tolerate optional data in T.
  3. Ensure capsule-react and the prompt builder agree on the item schema version.
  4. Check whether items come from LLM output and tighten the prompt/schema enforcement for that field.

Example fix

// before
serde_json::from_value::<T>(v.clone()) // element missing required field
// after
#[derive(Deserialize)]
struct Item { required: String, #[serde(default)] optional: Option<String> }
serde_json::from_value::<T>(v.clone())
Defensive patterns

Strategy: validation

Validate before calling

function isParseable(v) {
  try { JSON.parse(JSON.stringify(v)); return typeof v === 'object' && v !== null; }
  catch { return false; }
}

Type guard

fn parse_item<T: DeserializeOwned>(v: &serde_json::Value) -> Option<T> {
    serde_json::from_value::<T>(v.clone()).ok()
}

Try / catch

match serde_json::from_value::<T>(v.clone()) {
    Ok(item) => Some(item),
    Err(e) => { log::warn("Failed to parse {label} from prompt builder: {e}"); None }
}

Prevention

When it happens

Trigger: An element of the prompt-builder's JSON array does not deserialize into T — wrong field names/types for the expected struct, missing required fields, or an unexpected shape for that label.

Common situations: Prompt builder emitting a slightly different schema for one item kind; LLM-generated JSON with malformed entries mixed with valid ones; version drift between capsule-react and the prompt builder's output format.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


AI-assisted analysis of unicity-aos/aos-ce@f6f22024fb (2026-09-13). Data as JSON: /api/errors/309a7dab505869a0. Report an issue: GitHub.

Appendix: source

Thrown at capsules/capsule-react/src/lib.rs:2113

/// Parse a JSON array field from a payload, deserializing each element.
///
/// Logs a warning for each element that fails to deserialize and skips it.
/// Returns an empty vec if the field is missing or not an array.
fn parse_json_array_field<T: serde::de::DeserializeOwned>(
    payload: &serde_json::Value,
    key: &str,
    label: &str,
) -> Vec<T> {
    payload
        .get(key)
        .and_then(|v| v.as_array())
        .map(|arr| {
            arr.iter()
                .filter_map(|v| {
                    serde_json::from_value::<T>(v.clone())
                        .map_err(|e| {
                            log::warn(format!("Failed to parse {label} from prompt builder: {e}"));
                            e
                        })
                        .ok()
                })
                .collect()
        })
        .unwrap_or_default()
}

#[cfg(test)]
mod tests {
    use super::*;

    /// Build an `ActiveLlm` for tests without going through the registry.
    fn active(topic: &str, model: Option<&str>) -> ActiveLlm {
        ActiveLlm {
            topic: topic.to_string(),
            model: model.map(str::to_owned),

View on GitHub (pinned to f6f22024fb)