hcengineering/platform · error · serde::de::Error

Failed to deserialize as StandardPatchOperation: {}. Also fa

Error message

Failed to deserialize as StandardPatchOperation: {}. Also failed to deserialize as HulyPatchOperation: {}

What it means

PatchOperation supports two wire formats: the newer StandardPatchOperation and the legacy HulyPatchOperation. deserialize tries Standard first; if that fails it tries Huly, and if both fail it returns a combined error listing both serde messages so the caller can see why neither format matched.

Source

Thrown at foundations/hulylake/server/src/patch.rs:73

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PatchOperation {
    Huly(HulyPatchOperation),
    Standard(StandardPatchOperation),
}

impl<'de> serde::Deserialize<'de> for PatchOperation {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let value = Value::deserialize(deserializer)?;

        let op = serde_json::from_value::<StandardPatchOperation>(value.clone());
        if let Ok(op) = op {
            Ok(Self::Standard(op))
        } else {
            let standard_error = op.err().unwrap();
            serde_json::from_value::<HulyPatchOperation>(value)
                .map_err(|huly_error| {
                    serde::de::Error::custom(format!(
                        "Failed to deserialize as StandardPatchOperation: {}. Also failed to deserialize as HulyPatchOperation: {}",
                        standard_error, huly_error
                    ))
                })
                .map(Self::Huly)
        }
    }
}

#[derive(Debug, Error, PartialEq, Eq)]
pub enum HulyPatchError {
    #[error("invalid number")]
    InvalidNumber,
    #[error("patch error: {0}")]
    PatchError(String),

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Fix the patch payload to match the documented StandardPatchOperation schema
  2. Upgrade/align client and server versions so both agree on the patch format
  3. Read the two embedded serde errors to identify the exact missing/unknown field
  4. If legacy format is intentional, migrate the producer to the standard format

Example fix

// before
await fetch(url, { method: 'POST', body: JSON.stringify({ op: 'set ', attribute: 'name' }) }) // trailing space / wrong shape
// after
await fetch(url, { method: 'POST', body: JSON.stringify({ op: 'set', attribute: 'name', value: 'x' }) })
Defensive patterns

Strategy: validation

Validate before calling

function isValidPatch(p: unknown): boolean {
  return typeof p === 'object' && p !== null &&
    'op' in p && typeof (p as any).op === 'string' &&
    (ALLOWED_OPS as string[]).includes((p as any).op.trim())
}

Type guard

function isStandardPatch(v: unknown): v is StandardPatchOperation {
  return typeof v === 'object' && v !== null && typeof (v as any).op === 'string'
}

Try / catch

try {
  await sendPatch(patch)
} catch (err) {
  if (String(err).includes('Failed to deserialize')) {
    const [stdErr] = String(err).match(/StandardPatchOperation: ([^.]+\.)?/g) ?? []
    logger.error('patch rejected', { stdErr })
  }
}

Prevention

When it happens

Trigger: Submitting a patch payload that is neither a valid StandardPatchOperation nor a valid HulyPatchOperation — e.g. unknown 'op' verb, missing required fields like 'attribute' or 'operations', or a JSON shape from a mismatched client version.

Common situations: Older clients sending legacy patch formats after a server update; hand-crafted test payloads with typo'd fields; version skew between transactor/client and hulylake server.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29). Data as JSON: /api/errors/03d73d72ea6e5a24. Report an issue: GitHub.