astrid-runtime/astrid · error
native provider returned an invalid structured error
Error message
native provider returned an invalid structured error
What it means
When a native provider returns a Failure outcome, render_response validates the structured error: the code must be lowercase ASCII letters/digits/hyphens and the message must be non-empty, at most 4096 bytes, and free of control characters. If any check fails, the CLI cannot safely render the provider's error and bails with this generic message.
Source
Thrown at crates/astrid-cli/src/commands/storage.rs:327
}) => println!(
"mount {mount_id} at {}: {access:?}, dirty={dirty}",
mountpoint.display()
),
StorageProviderOutcomeV1::Success(StorageProviderSuccessV1::Unmounted { mount_id }) => {
println!("unmounted {mount_id}");
},
StorageProviderOutcomeV1::Failure(failure) => {
if failure.code.is_empty()
|| failure.code.len() > 64
|| !failure
.code
.bytes()
.all(|byte| byte.is_ascii_lowercase() || byte.is_ascii_digit() || byte == b'-')
|| failure.message.is_empty()
|| failure.message.len() > 4096
|| failure.message.chars().any(char::is_control)
{
bail!("native provider returned an invalid structured error");
}
eprintln!(
"storage provider error [{}]: {}",
failure.code, failure.message
);
return Ok(ExitCode::FAILURE);
},
}
Ok(ExitCode::SUCCESS)
}
fn platform_provider_name() -> &'static str {
#[cfg(target_os = "macos")]
{
"astrid-storage-provider-fskit"
}
#[cfg(target_os = "linux")]
{View on GitHub (pinned to affd8760f4)
Solutions
- Fix the provider to emit kebab-case error codes ([a-z0-9-]) and sanitize messages (strip control chars, truncate to 4096 bytes)
- Ensure the provider replaces newlines in error messages (e.g. with spaces) before serializing JSON
- Provide a meaningful non-empty fallback message when no detail is available
- Log the raw provider output separately if you control both sides, so invalid payloads can be diagnosed
Example fix
// before (provider)
message: format!("failed: \n{raw_os_error_output}"),
// after
let msg: String = raw_os_error_output.chars().filter(|c| !c.is_control()).take(4096).collect();
message: if msg.is_empty() { "unknown provider failure".into() } else { msg }, Defensive patterns
Strategy: validation
Validate before calling
fn structured_error_ok(code: &str, msg: &str) -> bool { code.bytes().all(|b| b.is_ascii_lowercase() || b.is_ascii_digit() || b == b'-') && !msg.is_empty() && msg.len() <= 4096 && !msg.chars().any(char::is_control) } Type guard
fn sane_failure(f: &StorageProviderFailureV1) -> Option<&StorageProviderFailureV1> { if structured_error_ok(&f.code, &f.message) { Some(f) } else { None } } Try / catch
match sane_failure(&failure) {
Some(f) => eprintln!("storage provider error [{}]: {}", f.code, f.message),
None => eprintln!("provider returned an unrenderable structured error"),
} Prevention
- Use a kebab-case code generator/enum in the provider
- Strip control characters and truncate messages to 4096 bytes on the provider side
- Never log raw OS error blobs directly into structured error messages
When it happens
Trigger: A provider Failure outcome has a code containing uppercase/underscore/space characters, or an empty/oversize (>4096 bytes) message, or a message containing control characters (e.g. embedded newline in provider JSON output) — validated in render_response, exercised by the fskit_gap/newline/oversize tests.
Common situations: Provider emits raw OS error strings containing newlines or terminal control codes; provider uses CamelCase or snake_case error codes instead of kebab-case; provider serializes a multi-MB log blob as the failure message; provider returns empty message when it has no detail.
Understand the failure class
Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.
Related errors
- FSKit service launch exceeds limit
- opaque capsule assets cannot be symlinks: {}
- unexpected response from kernel: {other:?}
- unexpected response from kernel: {other:?}
- unexpected response from kernel: {body:?}
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/865615e63c3d0785.
Report an issue: GitHub.