{"record":{"id":"bc203556f0449423","repo":"affaan-m/ECC","slug":"candidate-alias-collision-with-different-immutable","errorCode":null,"errorMessage":"candidate alias collision with different immutable target","messagePattern":"candidate alias collision with different immutable target","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ecc2/src/session/store.rs","lineNumber":5318,"sourceCode":"                \"SELECT 1 FROM harness_candidates WHERE id = ?1\",\n                [alias_id],\n                |_| Ok(()),\n            )\n            .optional()?\n            .is_some()\n        {\n            anyhow::bail!(\"candidate alias collision with physical candidate id\");\n        }\n        let existing = tx\n            .query_row(\n                \"SELECT candidate_id FROM harness_candidate_aliases WHERE alias_id = ?1\",\n                [alias_id],\n                |row| row.get::<_, String>(0),\n            )\n            .optional()?;\n        if let Some(existing) = existing {\n            if existing != candidate_id {\n                anyhow::bail!(\"candidate alias collision with different immutable target\");\n            }\n            return Ok(());\n        }\n        tx.execute(\n            \"INSERT INTO harness_candidate_aliases (alias_id, candidate_id, id_version, created_at) VALUES (?1, ?2, 2, ?3)\",\n            rusqlite::params![alias_id, candidate_id, chrono::Utc::now().to_rfc3339()],\n        )?;\n        Ok(())\n    }\n\n    fn resolve_harness_candidate_id(connection: &Connection, candidate_id: &str) -> Result<String> {\n        if let Some(target) = connection\n            .query_row(\n                \"SELECT candidate_id FROM harness_candidate_aliases WHERE alias_id = ?1\",\n                [candidate_id],\n                |row| row.get::<_, String>(0),\n            )\n            .optional()?","sourceCodeStart":5300,"sourceCodeEnd":5336,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/ecc2/src/session/store.rs#L5300-L5336","documentation":"Candidate aliases are immutable: once an alias_id maps to a candidate_id it can never be re-pointed. Registration loads any existing mapping for the alias; if the existing target differs from the requested candidate_id it bails 'candidate alias collision with different immutable target'. If it matches, registration is idempotent and returns Ok.","triggerScenarios":"registering the same alias_id for two different candidate_ids — e.g. reusing a well-known alias string for a new candidate, retrying registration after re-keying a candidate, or concurrent writers racing with different targets.","commonSituations":"Re-deploying configs where an alias was reassigned to a renamed candidate; build/tooling systems reusing stable short names across versions; two services independently claiming the same alias for different candidates.","solutions":["Look up the existing mapping first and only register when the target matches (the API already short-circuits idempotently).","Derive new alias strings when the target candidate changes (version-suffixed aliases) instead of reusing the old one.","Centralize alias creation behind one service/lock to avoid concurrent conflicting claims.","If you truly need to move an alias, add an explicit re-point API with deprecation of the old target — do not overwrite."],"exampleFix":"// before\n// blindly re-registering after re-keying the candidate\nstore.register_candidate_alias(&new_candidate_id, \"stable-alias\")?; // bails\n\n// after\nmatch store.lookup_candidate_by_alias(\"stable-alias\")? {\n    Some(id) if id != new_candidate_id => {\n        let alias = format!(\"stable-alias@{}\", new_candidate_id);\n        store.register_candidate_alias(&new_candidate_id, &alias)?;\n    }\n    _ => store.register_candidate_alias(&new_candidate_id, \"stable-alias\")?,\n}","handlingStrategy":"validation","validationCode":"if let Some(existing) = store.lookup_candidate_by_alias(alias_id)? {\n    ensure!(existing == candidate_id, \"alias {alias_id} is immutable and points to {existing}\");\n} // else safe to register (API is idempotent for matching targets)","typeGuard":null,"tryCatchPattern":"match store.register_candidate_alias(&cid, alias) {\n    Err(e) if e.to_string().contains(\"different immutable target\") => {\n        mint_new_versioned_alias(alias) // never re-point\n    }\n    other => other,\n}","preventionTips":["Treat alias->candidate mappings as immutable; never reuse an alias for a new candidate.","Version-suffix aliases when the underlying candidate is re-keyed.","Funnel alias registration through one service to avoid conflicting concurrent claims."],"tags":["sqlite","aliases","immutability","identifier-collision"],"backgroundTag":"internal-invariant-violation","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}