libnyanpasu/clash-nyanpasu · error
uid-derived path is always a valid managed path
Error message
uid-derived path is always a valid managed path
What it means
This is a panic raised by `.expect()` when converting a uid-derived string into a `ManagedProfilePath` during profile item updates in the profiles actor. The code asserts that any path of the form `"{uid}.{ext}"` built from an existing profile uid and a canonical extension is always valid under the managed-path rules (non-empty, sane length, no illegal segments). If this expect fires, the uid/extension produced a path violating `ManagedProfilePath::new` invariants, which the actor treats as an unrecoverable internal bug, not a user error.
Source
Thrown at backend/tauri/src/state/profiles/actor.rs:1911
}
}
ProfilesActorMessage::ReplaceDefinition {
uid,
definition,
reply,
} => {
let versioned = state.manager.snapshot_handle().load();
let expected_version = versioned.version;
let before = versioned.state.clone();
drop(versioned);
let result = match before.items.get(&uid) {
None => Err(ProfilesError::ProfileNotFound(uid.clone())),
Some(previous_item) => {
let previous_source = previous_item.definition.source().cloned();
let mut definition = definition;
let ext = Self::canonical_extension(&definition);
let canonical = ManagedProfilePath::new(format!("{uid}.{ext}"))
.expect("uid-derived path is always a valid managed path");
let same_slot = match (&previous_source, definition.source()) {
(Some(previous), Some(next)) => {
Self::retains_materialization(previous, next, &canonical)
}
_ => false,
};
if let Some(source) = definition.source_mut() {
let materialized = source.materialized_mut();
materialized.file = canonical.clone();
materialized.updated_at = if same_slot {
previous_source
.as_ref()
.and_then(|source| source.materialized().updated_at)
} else {
None
};
if let ProfileSource::Remote { subscription, .. } = source {
*subscription = match (same_slot, previous_source.as_ref()) {View on GitHub (pinned to f7dbce2997)
Solutions
- Inspect the profile item's uid and its definition source extension; delete or repair the offending profile entry in the profiles config file.
- Check `ManagedProfilePath::new` validation rules and confirm `canonical_extension` sanitizes/whitelists the extension before composing the path.
- Upgrade/repair the profiles data via the app's own migration rather than feeding legacy definitions into the update path.
- If reproducible, file a bug with the profile definition that triggers it — this is an internal invariant violation, not a supported input state.
Example fix
// before
let canonical = ManagedProfilePath::new(format!("{uid}.{ext}"))
.expect("uid-derived path is always a valid managed path");
// after
let canonical = ManagedProfilePath::new(format!("{uid}.{ext}"))
.map_err(|e| ProfilesError::InvalidManagedPath(uid.clone(), e.to_string()))?; Defensive patterns
Strategy: validation
Validate before calling
fn validate_uid_extension(uid: &str, ext: &str) -> Result<(), String> {
if uid.is_empty() || ext.is_empty() {
return Err("uid and extension must be non-empty".into());
}
let candidate = format!("{uid}.{ext}");
ManagedProfilePath::new(candidate).map(|_| ()).map_err(|e| e.to_string())
} Type guard
fn is_valid_managed_path(s: &str) -> bool {
ManagedProfilePath::new(s.to_owned()).is_ok()
} Try / catch
let canonical = ManagedProfilePath::new(format!("{uid}.{ext}"))
.map_err(|e| ProfilesError::InvalidManagedPath(uid.clone(), e.to_string()))?; Prevention
- Sanitize/whitelist the extension in `canonical_extension` so it can never contain path-illegal characters
- Validate uids when profiles are loaded/persisted, not at path-composition time
- Add a test feeding legacy/corrupted profile definitions through the update path
When it happens
Trigger: Calling the profile-item update path on the profiles actor (around actor.rs:1911) when a previous item lookup succeeded but `canonical_extension(&definition)` returns an extension containing path-illegal characters, or the uid itself is malformed/empty so the composed string fails `ManagedProfilePath::new` validation.
Common situations: A profile item persisted by an older app version carries a uid or source extension that fails newer path validation; a corrupted profiles.yaml or a hand-edited profile definition whose source yields a bogus extension (e.g. contains `/`, `..`, or is empty).
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- replacement target remains in the candidate snapshot
- legacy verge snapshot must serialize as a mapping
- failed to parse profiles: {e}
- semaphore should never closed
- version overflow
AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08).
Data as JSON: /api/errors/2b3b507736085e19.
Report an issue: GitHub.