astrid-runtime/astrid · error
region name too long
Error message
region name too long
What it means
When serializing a record, the region name is length-prefixed with a u16 on disk. append_from_inner converts the region name's byte length to u16 and fails with InvalidInput if the name exceeds 65535 bytes. This guards the on-disk record format, which cannot represent longer names.
Solutions
- Validate region names at your API boundary: reject names whose byte length exceeds 65535 (ideally far lower) before creating/writing the region.
- Truncate or hash long identifiers into a bounded name (e.g. blake3/sha256 hex, ≤64 chars) instead of using raw long strings.
- Count bytes, not characters, when validating names with non-ASCII content.
- Check where the name is assembled; cap the size of each concatenated component.
Example fix
// before
let name = format!("regions/{}:{}:{}", tenant, path, full_blob_id);
volume.write_region_from(&name, offset, payload)?;
// after
let digest = blake3::hash(full_blob_id.as_bytes()).to_hex()[..32].to_string();
let name = format!("r/{}:{}", tenant_short, digest);
assert!(name.len() <= 255);
volume.write_region_from(&name, offset, payload)?; Defensive patterns
Strategy: validation
Validate before calling
// Rust: validate name before calling the volume API
fn valid_region_name(name: &str) -> bool {
!name.is_empty() && name.len() <= 255 // byte length, well under u16::MAX
}
if !valid_region_name(®ion) { return Err("region name too long"); } Try / catch
match volume.write_region_from(®ion, offset, payload).await {
Err(e) if e.kind() == io::ErrorKind::InvalidInput && e.to_string().contains("region name too long") => {
// hash/shorten the identifier and retry with a bounded name
}
other => other?,
} Prevention
- Validate region-name byte length at your API boundary (cap far below 65535).
- Hash long identifiers instead of embedding raw paths/user input in names.
- Remember byte length != character count for non-ASCII names.
- Add a unit test covering the maximum accepted name length.
When it happens
Trigger: append_from (via append_from_inner) is given a region whose as_str().as_bytes() length is > 65535 — callers constructing region names from unbounded user input, concatenations, or long identifiers.
Common situations: User-supplied or templated region names pasted into the volume API without validation; generated names built by concatenating prefixes/IDs that grow unbounded; names containing multi-byte UTF-8 whose byte length (not char count) exceeds the limit.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- region name too long
- Astrid volume is not a regular file
- durable capsule metadata names a hash for a non-WASM…
- FUSE provider control path is not canonical
- invalid Astrid volume header
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/bb301915db1afd34.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-storage/src/volume/hosted/stream.rs:101
},
}
}
fn append_from_inner(
state: &mut ContainerState,
operation: Operation,
region: &VolumeRegion,
offset: u64,
payload_len: u64,
payload: &mut dyn Read,
) -> io::Result<(u64, u64)> {
let next_sequence = state
.sequence
.checked_add(1)
.ok_or_else(|| io::Error::other("Astrid volume sequence exhausted"))?;
let name = region.as_str().as_bytes();
let name_len = u16::try_from(name.len())
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "region name too long"))?;
let total_len = u64::try_from(RECORD_FIXED_BYTES)
.ok()
.and_then(|fixed| fixed.checked_add(u64::from(name_len)))
.and_then(|total| total.checked_add(payload_len))
.ok_or_else(|| io::Error::other("volume record length overflow"))?;
let mut hasher = blake3::Hasher::new_derive_key("astrid volume record v1");
hasher.update(&next_sequence.to_le_bytes());
hasher.update(&[operation as u8]);
hasher.update(&name_len.to_le_bytes());
hasher.update(&offset.to_le_bytes());
hasher.update(&payload_len.to_le_bytes());
hasher.update(name);
// The previous footer ends at `valid_len`; remove it before publishing a
// new record. A failed stream leaves footer_pending set so the next sync
// restores the prior durable footer.
state.flush_state = super::FlushState::Required;
state.footer_pending = true;View on GitHub (pinned to affd8760f4)