{"record":{"id":"d7373a45716e4223","repo":"xai-org/grok-build","slug":"workflow-source-already-registered-run-id","errorCode":null,"errorMessage":"workflow source already registered: {run_id}","messagePattern":"workflow source already registered: (.+?)","errorType":"validation","errorClass":"std::io::Error","httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-shell/src/session/workflow/store.rs","lineNumber":133,"sourceCode":"                    state.token_leases.clear();\n                    state.agent_usage_incomplete = true;\n                }\n                states.push(state);\n            }\n        }\n        (store, states)\n    }\n\n    pub(crate) fn register(\n        &self,\n        run_id: &str,\n        script: &str,\n        args: &serde_json::Value,\n        effort: Option<ReasoningEffort>,\n    ) -> io::Result<()> {\n        validate_run_id(run_id)?;\n        if self.sources.lock().contains_key(run_id) {\n            return Err(io::Error::new(\n                io::ErrorKind::AlreadyExists,\n                format!(\"workflow source already registered: {run_id}\"),\n            ));\n        }\n\n        if let Some(run_dir) = self.run_dir(run_id) {\n            let scripts_dir = run_dir.join(\"scripts\");\n            std::fs::create_dir_all(&scripts_dir)?;\n            let args_json = serde_json::to_vec_pretty(args).map_err(io::Error::other)?;\n            atomic_write_new(&run_dir.join(\"args.json\"), &args_json)?;\n            if let Some(effort) = effort {\n                atomic_write_new(&run_dir.join(\"effort\"), effort.as_str().as_bytes())?;\n            }\n            atomic_write_new(&script_revision_path(&run_dir, 0), script.as_bytes())?;\n            atomic_write_replace(&run_dir.join(\"script.rhai\"), script.as_bytes())?;\n        }\n\n        self.sources.lock().insert(","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-shell/src/session/workflow/store.rs#L115-L151","documentation":"WorkflowStore::register validates the run_id and then rejects registration if a source for that run_id is already present in its in-memory sources map, returning io::ErrorKind::AlreadyExists with the run_id. Each workflow run must have exactly one registered resume source (script/args/effort).","triggerScenarios":"Calling register twice with the same run_id — e.g. re-registering on resume, a retried registration, or two components both registering the same run.","commonSituations":"Retry logic that re-invokes register after a transient failure that actually succeeded; resuming a run whose source was already registered in this process; duplicate event handling registering the same run_id twice.","solutions":["Check store has source / contains-key for the run_id first and skip re-registration","Treat AlreadyExists as idempotent success if script and args match the existing registration","Use a fresh run_id for genuinely new runs (e.g. UUIDv7 per run)","If re-registration is legitimate, add an unregister/replace API instead of calling register again"],"exampleFix":"// before\nstore.register(&run_id, &script, &args, effort)?; // panics/fails on resume\n// after\nif store.source(&run_id).is_none() {\n    store.register(&run_id, &script, &args, effort)?;\n}","handlingStrategy":"validation","validationCode":"if store.source(&run_id).is_some() {\n    // already registered: skip or verify script/args match\n} else {\n    store.register(&run_id, &script, &args, effort)?;\n}","typeGuard":"fn is_registered(store: &WorkflowStore, run_id: &str) -> bool {\n    store.source(run_id).is_some()\n}","tryCatchPattern":"match store.register(&run_id, &script, &args, effort) {\n    Err(e) if e.kind() == io::ErrorKind::AlreadyExists => { /* idempotent: verify and continue */ }\n    other => other?,\n}","preventionTips":["Make registration idempotent: check before register, treat AlreadyExists as success when script/args match","Issue a fresh run_id (UUIDv7) per run so duplicate ids never occur","Guard retry logic so a retried register call short-circuits on AlreadyExists","Register exactly once per run lifecycle, in one owner component"],"tags":["duplicate-key","idempotency","workflow","io"],"backgroundTag":"duplicate-key-already-exists","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}