astrid-runtime/astrid · error

volume metadata transaction must contain 1 to 1024 mutations

Error message

volume metadata transaction must contain 1 to 1024 mutations

What it means

commit_metadata validates that a metadata transaction batch contains between 1 and MAX_METADATA_MUTATIONS (1024) mutations before acquiring the volume state lock. An empty batch carries no work, and batches over 1024 exceed the fixed encoding limit, so the library rejects both with InvalidInput up front. The mutation is not applied and volume state is untouched.

Source

Thrown at crates/astrid-storage/src/volume/hosted/mod.rs:386

        }
        Self::append(
            &mut state,
            Operation::Replace,
            source,
            0,
            destination.as_str().as_bytes(),
        )?;
        let source_state = state
            .regions
            .remove(source)
            .ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, source.as_str()))?;
        state.regions.insert(destination.clone(), source_state);
        Ok(())
    }

    fn commit_metadata(&self, mutations: &[VolumeMetadataMutation]) -> io::Result<()> {
        if mutations.is_empty() || mutations.len() > MAX_METADATA_MUTATIONS {
            return Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "volume metadata transaction must contain 1 to 1024 mutations",
            ));
        }
        let mut state = self.state.lock();
        let mut next_regions = state.regions.clone();
        apply_metadata_mutations(&mut next_regions, mutations)?;
        let payload = encode_metadata_mutations(mutations)?;
        let transaction = VolumeRegion::new(METADATA_TRANSACTION_REGION)?;
        Self::append(
            &mut state,
            Operation::MetadataTransaction,
            &transaction,
            0,
            &payload,
        )?;
        state.regions = next_regions;
        Ok(())

View on GitHub (pinned to affd8760f4)

Solutions

  1. Check mutations.is_empty() before calling and return early (or skip the call) when there is nothing to commit.
  2. Batch mutations into chunks of at most 1024 and call commit_metadata once per chunk.
  3. If >1024 mutations are routine, redesign the caller to commit incrementally rather than accumulating one giant transaction.

Example fix

// before
volume.commit_metadata(&mutations)?;
// after
for chunk in mutations.chunks(1024) {
    if chunk.is_empty() { continue; }
    volume.commit_metadata(chunk)?;
}
Defensive patterns

Strategy: validation

Validate before calling

fn can_commit(mutations: &[VolumeMetadataMutation]) -> bool {
    !mutations.is_empty() && mutations.len() <= 1024
}

Prevention

When it happens

Trigger: Calling commit_metadata(&[]) with an empty slice, or calling it with more than 1024 VolumeMetadataMutation entries in one transaction.

Common situations: Code that collects mutations into a Vec and calls commit_metadata unconditionally without checking the Vec is non-empty (e.g. a rename sweep that found nothing to do); bulk tools that try to push thousands of renames in a single transaction instead of batching.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/9f14633291db807e. Report an issue: GitHub.