zeroclaw-labs/zeroclaw · error · anyhow::Error

SOP '{}' already exists

Error message

SOP '{}' already exists

What it means

create_sop deliberately refuses to overwrite: it checks whether the resolved SOP directory already exists and bails before delegating to save_sop. This is the create-or-refuse counterpart to save_sop, which overwrites unconditionally after validation.

Source

Thrown at crates/zeroclaw-runtime/src/sop/mod.rs:276

    load_sop(&resolve_sop_dir(sops_dir, name)?, default_execution_mode)
}

/// Delete an SOP's directory (manifest, steps, everything). Errors if no
/// SOP with that name exists.
pub fn delete_sop(sops_dir: &Path, name: &str) -> Result<()> {
    let dir = resolve_sop_dir(sops_dir, name)?;
    if !dir.exists() {
        anyhow::bail!("SOP '{name}' not found");
    }
    std::fs::remove_dir_all(&dir)?;
    Ok(())
}

/// Create a new SOP on disk, refusing to overwrite an existing one. Same
/// normalization and validation as `save_sop`.
pub fn create_sop(sops_dir: &Path, sop: &Sop) -> Result<()> {
    if resolve_sop_dir(sops_dir, &sop.name)?.exists() {
        anyhow::bail!("SOP '{}' already exists", sop.name);
    }
    save_sop(sops_dir, sop)
}

/// Typed classification of an authoring failure so transports map it to the
/// right status/RPC code without matching on stringified message substrings.
#[derive(Debug)]
pub enum SopAuthorError {
    AlreadyExists(String),
    NotFound(String),
    Other(anyhow::Error),
}

impl std::fmt::Display for SopAuthorError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            SopAuthorError::AlreadyExists(name) => write!(f, "SOP '{name}' already exists"),
            SopAuthorError::NotFound(name) => write!(f, "SOP '{name}' not found"),

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. If overwriting is intended, call save_sop directly (it validates then overwrites).
  2. Otherwise pick a distinct name/versioned slug and create under that name.
  3. Check existence first and branch: skip creation when the SOP is already present.

Example fix

// before: bootstrap fails on second run
create_sop(&sops_dir, &sop)?;

// after: create only when absent, refresh otherwise
if !resolve_sop_dir(&sops_dir, &sop.name)?.exists() {
    create_sop(&sops_dir, &sop)?;
} else {
    save_sop(&sops_dir, &sop)?; // validate + overwrite
}
Defensive patterns

Strategy: validation

Validate before calling

if resolve_sop_dir(&sops_dir, &sop.name)?.exists() {
    // decide explicitly: refresh via save_sop, or bail with context
    save_sop(&sops_dir, &sop)?;
} else {
    create_sop(&sops_dir, &sop)?;
}

Try / catch

match create_sop(&sops_dir, &sop) {
    Err(e) if e.to_string().contains("already exists") => {
        // pick a new name, or intentionally overwrite via save_sop
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling create_sop with a name that already has a directory under sops_dir: re-running a bootstrap script, provisioning twice, or creating an SOP whose name collides with an existing one.

Common situations: Setup scripts that run repeatedly; two teams authoring SOPs with the same slug; re-importing an SOP pack that was already installed.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/0702f3712c1e0a99. Report an issue: GitHub.