rustfs/rustfs · error · RedactionError
Redaction refused the document: its node count exceeds the f
Error message
Redaction refused the document: its node count exceeds the frozen budget of 4096.
What it means
Redaction counts every map entry, array element, and scalar it visits, and refuses the document once the count passes 4096 (MAX_NODES, redaction.rs:29). The count is taken after unregistered top-level fields are dropped, so only content under allowed fields matters. The budget bounds redaction work deterministically under the frozen D05 contract.
Source
Thrown at rustfs/src/connect/offline/redaction.rs:170
#[serde(rename_all = "camelCase")]
pub struct RedactionResult {
pub document: Map<String, Value>,
pub canonical_json: String,
pub redaction_version: &'static str,
pub ruleset_hash: &'static str,
pub redacted_count: usize,
pub counts: RedactionCounts,
}
#[derive(Clone, Copy, Debug, Error, PartialEq, Eq)]
pub enum RedactionError {
#[error("Redaction refused the document: it names no registered collection surface.")]
UnknownSurface,
#[error("Redaction refused the document: its size in bytes exceeds the frozen budget of 262144.")]
InputTooLarge,
#[error("Redaction refused the document: its nesting depth exceeds the frozen budget of 8.")]
TooDeep,
#[error("Redaction refused the document: its node count exceeds the frozen budget of 4096.")]
TooManyNodes,
#[error("Redaction refused the document: it is not representable as JSON.")]
NotRepresentable,
}
pub(super) fn redact(source: RedactionSource, document: &Map<String, Value>) -> Result<RedactionResult, RedactionError> {
let encoded = serde_json::to_vec(document).map_err(|_| RedactionError::NotRepresentable)?;
if encoded.len() > MAX_INPUT_BYTES {
return Err(RedactionError::InputTooLarge);
}
let mut counts = RedactionCounts::default();
let allowed = document
.iter()
.filter_map(|(key, value)| {
if source.allows(key) {
Some((key.clone(), value.clone()))
} else {View on GitHub (pinned to 201c653dcd)
Solutions
- Aggregate at the producer: send coarse counts and summaries instead of one node per drive or interface.
- Cap list lengths (top-N entries) before building the document.
- If the surface genuinely needs the detail, chunk it into several documents, each under 4096 nodes.
Example fix
// before
doc.insert("filesystemSummary", json!(per_mount_details)); // 4096+ nodes -> TooManyNodes
// after
doc.insert("filesystemSummary", json!(summarize_filesystems(&per_mount_details))); // aggregated, small Defensive patterns
Strategy: validation
Validate before calling
fn count_nodes(value: &serde_json::Value) -> usize {
match value {
serde_json::Value::Object(m) => 1 + m.values().map(count_nodes).sum::<usize>(),
serde_json::Value::Array(a) => 1 + a.iter().map(count_nodes).sum::<usize>(),
_ => 1,
}
}
// submit only when the allowed fields' subtrees total at most 4096 nodes Try / catch
match redact(source, &document) {
Err(RedactionError::TooManyNodes) => { /* aggregate or chunk; the same payload will always fail */ }
other => other,
} Prevention
- Count nodes of generated documents in producer tests with worst-case cluster fixtures.
- Store aggregated summaries, never raw per-device tables.
- Remember dropped top-level fields cost nothing: only allowed fields' content is counted.
When it happens
Trigger: redact walking an allowed field whose value tree exceeds 4096 nodes in total - for example a filesystemSummary or networkSummary holding hundreds of entries each serialized as an object with many keys (count_node at redaction.rs:230 trips).
Common situations: Large clusters emitting full per-drive or per-interface detail; producers echoing raw df, mount, or netstat tables into the document; a version change that starts including per-node breakdowns.
Related errors
- Redaction refused the document: its size in bytes exceeds th
- Redaction refused the document: its nesting depth exceeds th
- Redaction refused the document: it is not representable as J
- Connect heartbeat state at {path} is invalid: {source}
- Redaction refused the document: it names no registered colle
AI-assisted analysis of rustfs/rustfs@201c653dcd (2026-08-23).
Data as JSON: /api/errors/677ce89f4f7a47e7.
Report an issue: GitHub.