libnyanpasu/clash-nyanpasu · error
invalid profile cleanup operation id
Error message
invalid profile cleanup operation id
What it means
locate_cleanup validates the operation id before probing the filesystem: ids must match the library's strict format (valid_operation_id, typically a fixed charset/length token). If the caller passes a malformed id, the library bails immediately rather than constructing paths from untrusted input. This is an input-validation guard that also prevents path traversal via crafted ids.
Source
Thrown at backend/tauri/src/service/profile_file.rs:1332
fn active_managed_paths(profiles: &Profiles) -> HashSet<ManagedProfilePath> {
profiles
.items
.values()
.filter_map(|item| {
item.definition
.source()
.map(|source| source.materialized().file.clone())
})
.collect()
}
fn locate_cleanup(
root: &Path,
operation_id: &str,
) -> anyhow::Result<Option<(CleanupPhase, MaterializationJournal)>> {
if !valid_operation_id(operation_id) {
bail!("invalid profile cleanup operation id");
}
let pending_path = Self::cleanup_path(root, CleanupPhase::Pending, operation_id);
let ready_path = Self::cleanup_path(root, CleanupPhase::Ready, operation_id);
let pending = match std::fs::symlink_metadata(&pending_path) {
Ok(metadata) if !is_symlink_or_reparse(&metadata) && metadata.is_file() => {
Some(Self::read_journal(&pending_path, operation_id)?)
}
Ok(_) => bail!("pending cleanup journal is not a regular file"),
Err(error) if error.kind() == std::io::ErrorKind::NotFound => None,
Err(error) => return Err(error).context("inspect pending cleanup journal"),
};
let ready = match std::fs::symlink_metadata(&ready_path) {
Ok(metadata) if !is_symlink_or_reparse(&metadata) && metadata.is_file() => {
Some(Self::read_journal(&ready_path, operation_id)?)
}
Ok(_) => bail!("ready cleanup journal is not a regular file"),
Err(error) if error.kind() == std::io::ErrorKind::NotFound => None,
Err(error) => return Err(error).context("inspect ready cleanup journal"),View on GitHub (pinned to f7dbce2997)
Solutions
- Pass the operation id exactly as it was returned by the API that created the cleanup operation; do not trim, rename, or reformat it.
- Validate the id yourself before calling: check it is non-empty and matches the expected token pattern (alphanumeric, fixed length).
- If recovering from disk, extract the id with the library's own listing/parsing helpers (e.g. list_operation_ids) instead of string-splitting file names.
- Reject or sanitize user-supplied ids at the UI/IPC boundary before they reach recovery code.
Example fix
// before
let id = &file_name; // "pending-abc123.journal"
locate_cleanup(root, id)?;
// after
let id = parse_operation_id(&file_name)?; // extract the bare token
if !valid_operation_id(&id) { return Err(anyhow!("bad id")); }
locate_cleanup(root, &id)?; Defensive patterns
Strategy: validation
Validate before calling
fn valid_operation_id(id: &str) -> bool {
!id.is_empty()
&& id.len() <= 64
&& id.chars().all(|c| c.is_ascii_alphanumeric() || c == '-')
&& !id.starts_with('-')
} Try / catch
match locate_cleanup(root, id) {
Err(e) if e.to_string() == "invalid profile cleanup operation id" => {
// reject the input at the API boundary; do not retry with the same id
}
other => other,
} Prevention
- Always take operation ids from the API response that created the operation
- Parse ids out of file names with the library's helpers, not string splitting
- Validate user/IPC-supplied ids before invoking recovery
- Regenerate ids rather than trimming or reformatting existing ones
When it happens
Trigger: Calling the cleanup-lookup/recovery API with an operation id that is empty, contains characters outside the allowed set (path separators, '..', non-ASCII), or has the wrong length — e.g. passing a user-supplied string, a file name parsed loosely from a directory listing, or a truncated id.
Common situations: Feeding a journal file name that still contains a phase prefix or extension into the lookup; logging/telemetry code echoing a user-controlled id into recovery; hand-written tests using ids like "test" or "123" that don't satisfy the format; upgrading versions where id generation changed.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- pending cleanup journal is not a regular file
- ready cleanup journal is not a regular file
- active materialization target diverged before recovery
AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08).
Data as JSON: /api/errors/4221467f29fe4069.
Report an issue: GitHub.