paperclipai/paperclip · error · io::Error

runner diagnostics path is not a real directory

Error message

runner diagnostics path is not a real directory

What it means

Guard in verify_private_diagnostics_directory (paperclip-runnerd): symlink_metadata shows the diagnostics directory path is a symlink or not a directory. The runner refuses to write diagnostics into a path that is not a real directory because symlinked targets could redirect sensitive runner diagnostics elsewhere.

Source

Thrown at packages/paperclip-runner/runner/crates/runner-core/src/bin/paperclip-runnerd.rs:50

        return diagnostic;
    }
    let suffix = "…[truncated]";
    let byte_limit = RUNNER_DIAGNOSTIC_MAX_BYTES.saturating_sub(suffix.len());
    let boundary = diagnostic
        .char_indices()
        .map(|(index, _)| index)
        .take_while(|index| *index <= byte_limit)
        .last()
        .unwrap_or(0);
    diagnostic.truncate(boundary);
    diagnostic.push_str(suffix);
    diagnostic
}

fn verify_private_diagnostics_directory(directory: &Path) -> io::Result<()> {
    let metadata = fs::symlink_metadata(directory)?;
    if metadata.file_type().is_symlink() || !metadata.is_dir() {
        return Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            "runner diagnostics path is not a real directory",
        ));
    }
    #[cfg(unix)]
    if metadata.permissions().mode() & 0o077 != 0 {
        return Err(io::Error::new(
            io::ErrorKind::PermissionDenied,
            "runner diagnostics directory is accessible by group or other users",
        ));
    }
    Ok(())
}

fn persist_runner_diagnostic(directory: &Path, message: &str) -> io::Result<()> {
    verify_private_diagnostics_directory(directory)?;
    let destination = directory.join("runnerd.stderr.log");
    let contents = bounded_redacted_diagnostic(message);

View on GitHub (pinned to 01ad858492)

Solutions

  1. Point the diagnostics directory setting at a real, non-symlinked directory
  2. Replace the symlink with an actual directory (bind-mount or move the target) and restart runnerd
  3. Create the directory if it does not exist before starting the daemon
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at packages/paperclip-runner/runner/crates/runner-core/src/bin/paperclip-runnerd.rs:50 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10). Data as JSON: /api/errors/ad14bc26df0af420. Report an issue: GitHub.