libnyanpasu/clash-nyanpasu · error

managed target is not replaceable: {}

Error message

managed target is not replaceable: {}

What it means

`ensure_replaceable_target` allows a managed path to be absent, a regular file, or a plain symlink before the materialization step replaces it. Any other entry type (a real directory, special file) cannot be replaced by the file/symlink write path, so the code fails with this error. It usually means a directory exists where a managed profile file/symlink should be.

Source

Thrown at backend/tauri/src/service/profile_file.rs:725

            }
            Ok(_) => bail!("managed target is not a file: {}", path.display()),
            Err(error) if error.kind() == std::io::ErrorKind::NotFound => {
                Ok(ABSENT_HASH.to_owned())
            }
            Err(error) => Err(error).with_context(|| format!("inspect {}", path.display())),
        }
    }

    fn ensure_replaceable_target(path: &Path) -> anyhow::Result<()> {
        match std::fs::symlink_metadata(path) {
            Ok(metadata) if metadata.file_type().is_symlink() || metadata.is_file() => Ok(()),
            Ok(metadata) if is_symlink_or_reparse(&metadata) => {
                bail!(
                    "managed target is an unsupported reparse point: {}",
                    path.display()
                )
            }
            Ok(_) => bail!("managed target is not replaceable: {}", path.display()),
            Err(error) if error.kind() == std::io::ErrorKind::NotFound => Ok(()),
            Err(error) => Err(error).with_context(|| format!("inspect {}", path.display())),
        }
    }

    fn stage_resource(
        root: &Path,
        operation_id: &str,
        resource: &MaterializationResource,
    ) -> anyhow::Result<()> {
        match resource {
            MaterializationResource::File { content } => Self::write_private_file_new(
                &Self::stage_file_path(root, operation_id),
                content.as_bytes(),
            ),
            MaterializationResource::Symlink { target } => Self::write_private_file_new(
                &Self::stage_link_path(root, operation_id),
                target.as_str().as_bytes(),

View on GitHub (pinned to f7dbce2997)

Solutions

  1. Move or delete the directory at the reported path (`rm -r` / `Remove-Item -Recurse`) after preserving any needed contents
  2. Re-run the profile materialization so the app creates the expected file/symlink
  3. Configure other tooling not to place directories at this path
  4. Verify the profile's managed path points to a file location

Example fix

// before: directory at managed path
~/.config/nyanpasu/profiles/config.yaml/  (directory)
// after
mv ~/.config/nyanpasu/profiles/config.yaml ~/config.yaml.saved
# re-run materialization; app recreates config.yaml as a file/symlink
Defensive patterns

Strategy: validation

Validate before calling

fn path_is_replaceable(path: &std::path::Path) -> bool {
    match std::fs::symlink_metadata(path) {
        Ok(md) => md.is_file() || md.file_type().is_symlink(),
        Err(e) => e.kind() == std::io::ErrorKind::NotFound,
    }
}
// directories fail this pre-check

Type guard

fn replaceable(md: &std::fs::Metadata) -> bool {
    md.is_file() || md.file_type().is_symlink()
}

Try / catch

if let Err(e) = materialize_profile(...) {
    if e.to_string().contains("not replaceable") {
        // a directory/other occupies the path: back up and remove it, then retry
    } else { return Err(e); }
}

Prevention

When it happens

Trigger: Materialization calls `ensure_replaceable_target` and the path exists as a non-file, non-symlink entry — typically a directory created by the user or another tool at the managed profile path (e.g. `.../profiles/config.yaml/`).

Common situations: User created a folder with the managed file's name; other applications/dotfile managers replaced files with directories; leftover state from a previous schema that used directories.

Related errors


AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08). Data as JSON: /api/errors/f44659b8fae432db. Report an issue: GitHub.