{"record":{"id":"0702f3712c1e0a99","repo":"zeroclaw-labs/zeroclaw","slug":"sop-already-exists","errorCode":null,"errorMessage":"SOP '{}' already exists","messagePattern":"SOP '(.+?)' already exists","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-runtime/src/sop/mod.rs","lineNumber":276,"sourceCode":"    load_sop(&resolve_sop_dir(sops_dir, name)?, default_execution_mode)\n}\n\n/// Delete an SOP's directory (manifest, steps, everything). Errors if no\n/// SOP with that name exists.\npub fn delete_sop(sops_dir: &Path, name: &str) -> Result<()> {\n    let dir = resolve_sop_dir(sops_dir, name)?;\n    if !dir.exists() {\n        anyhow::bail!(\"SOP '{name}' not found\");\n    }\n    std::fs::remove_dir_all(&dir)?;\n    Ok(())\n}\n\n/// Create a new SOP on disk, refusing to overwrite an existing one. Same\n/// normalization and validation as `save_sop`.\npub fn create_sop(sops_dir: &Path, sop: &Sop) -> Result<()> {\n    if resolve_sop_dir(sops_dir, &sop.name)?.exists() {\n        anyhow::bail!(\"SOP '{}' already exists\", sop.name);\n    }\n    save_sop(sops_dir, sop)\n}\n\n/// Typed classification of an authoring failure so transports map it to the\n/// right status/RPC code without matching on stringified message substrings.\n#[derive(Debug)]\npub enum SopAuthorError {\n    AlreadyExists(String),\n    NotFound(String),\n    Other(anyhow::Error),\n}\n\nimpl std::fmt::Display for SopAuthorError {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            SopAuthorError::AlreadyExists(name) => write!(f, \"SOP '{name}' already exists\"),\n            SopAuthorError::NotFound(name) => write!(f, \"SOP '{name}' not found\"),","sourceCodeStart":258,"sourceCodeEnd":294,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-runtime/src/sop/mod.rs#L258-L294","documentation":"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.","triggerScenarios":"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.","commonSituations":"Setup scripts that run repeatedly; two teams authoring SOPs with the same slug; re-importing an SOP pack that was already installed.","solutions":["If overwriting is intended, call save_sop directly (it validates then overwrites).","Otherwise pick a distinct name/versioned slug and create under that name.","Check existence first and branch: skip creation when the SOP is already present."],"exampleFix":"// before: bootstrap fails on second run\ncreate_sop(&sops_dir, &sop)?;\n\n// after: create only when absent, refresh otherwise\nif !resolve_sop_dir(&sops_dir, &sop.name)?.exists() {\n    create_sop(&sops_dir, &sop)?;\n} else {\n    save_sop(&sops_dir, &sop)?; // validate + overwrite\n}","handlingStrategy":"validation","validationCode":"if resolve_sop_dir(&sops_dir, &sop.name)?.exists() {\n    // decide explicitly: refresh via save_sop, or bail with context\n    save_sop(&sops_dir, &sop)?;\n} else {\n    create_sop(&sops_dir, &sop)?;\n}","typeGuard":null,"tryCatchPattern":"match create_sop(&sops_dir, &sop) {\n    Err(e) if e.to_string().contains(\"already exists\") => {\n        // pick a new name, or intentionally overwrite via save_sop\n    }\n    other => other?,\n}","preventionTips":["Make bootstrap scripts check existence before creating.","Use versioned slugs when re-importing packs.","Reserve create_sop for first install; use save_sop for updates."],"tags":["sop","create","already-exists","conflict"],"backgroundTag":"duplicate-entity","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}