rustfs/rustfs · error · TierProbeIntentError

tier probe intent json error: {0}

Error message

tier probe intent json error: {0}

What it means

TierProbeIntentError::Json wraps a serde_json::Error produced while serializing an intent (encode) or deserializing a persisted envelope/inner intent (decode). Because PersistedTierProbeIntent and TierProbeIntent use #[serde(deny_unknown_fields)] and tagged enums, this fires for malformed JSON, missing or unknown fields, and fields of the wrong type. It means the stored bytes are not a valid tier probe intent envelope under the strict schema.

Source

Thrown at crates/ecstore/src/services/tier/tier_probe_intent.rs:49

pub(crate) const MAX_TIER_PROBE_INTENT_SIZE: usize = 64 * 1024;
const TIER_PROBE_OBJECT_PREFIX: &str = "rustfs-tier-probe-";

pub(crate) type Result<T> = std::result::Result<T, TierProbeIntentError>;

#[derive(Debug, thiserror::Error)]
pub(crate) enum TierProbeIntentError {
    #[error("tier probe intent is corrupt: {0}")]
    Corrupt(&'static str),
    #[error("tier probe intent schema is unsupported: {0}")]
    UnsupportedSchema(String),
    #[error("tier probe intent checksum mismatch")]
    ChecksumMismatch,
    #[error("invalid tier probe intent state change from {from:?} to {to:?}")]
    InvalidStateChange {
        from: TierProbeIntentState,
        to: TierProbeIntentState,
    },
    #[error("tier probe intent json error: {0}")]
    Json(#[from] serde_json::Error),
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub(crate) enum TierProbeIntentState {
    UploadOutcomeUnknown,
    Uploaded,
    CleanupPending,
    AbortedNoRemote,
    Completed,
}

#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub(crate) enum TierProbeRemoteVersionKind {
    #[default]
    Unknown,

View on GitHub (pinned to 5dca076efe)

Solutions

  1. Read the wrapped serde_json message — it names the exact path, field, and reason (unknown field, missing field, invalid type).
  2. Remove unknown fields and restore all required fields with correct types, matching the deny_unknown_fields strict schema.
  3. If the record was hand-edited or written by foreign tooling, delete it and re-run the tier probe rather than patching JSON in place.
  4. If corruption is suspected rather than editing, heal the erasure set / restore from a quorum copy of the metadata object.

Example fix

// before: extra/misspelled fields rejected by deny_unknown_fields
{"schema":"rustfs-tier-probe-intent-v1","content_sha256":"...","intent":{...,"tier_namee":"COLD-A"}}
// after: strict, canonical envelope with only known fields
{"schema":"rustfs-tier-probe-intent-v1","content_sha256":"<sha256-of-intent-json>","intent":{"probe_id":"...","revision":1,"state":"upload_outcome_unknown",/* all required fields, exact names */}}
Defensive patterns

Strategy: try-catch

Validate before calling

fn is_strict_envelope(data: &[u8]) -> bool {
    serde_json::from_slice::<PersistedTierProbeIntent>(data).is_ok()
}

Try / catch

match TierProbeIntent::decode(probe_id, &data) {
    Ok(intent) => use_intent(intent),
    Err(TierProbeIntentError::Json(e)) => {
        tracing::warn!(error = %e, "tier probe intent envelope failed strict JSON parse");
        delete_corrupt_record_and_reprobe(probe_id).await?;
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: decode on bytes that are not valid JSON or whose envelope/intent has an unknown field (deny_unknown_fields), a missing required field (e.g. old_config_etag in an add operation identity), a wrongly typed field, or an invalid tag for the TierProbeOperationIdentity tagged enum; encode when a nested value fails to serialize (rare, e.g. non-string map keys).

Common situations: Hand-editing a record and adding an extra field or misspelling a key; tooling that rewrites meta-bucket objects with pretty-printed or restructured JSON; corruption that breaks JSON syntax mid-file; writing records with a different serde layout than the reader expects.

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 rustfs/rustfs@5dca076efe (2026-09-06). Data as JSON: /api/errors/7b23bb37c0131aab. Report an issue: GitHub.