{"record":{"id":"cd1b8e8e4b2e1cd1","repo":"shareAI-lab/learn-claude-code","slug":"could-not-allocate-a-unique-workflow-runid","errorCode":null,"errorMessage":"could not allocate a unique workflow runId","messagePattern":"could not allocate a unique workflow runId","errorType":"exception","errorClass":"WorkflowInputError","httpStatus":null,"severity":"error","filePath":"s16_workflow_runtime/code.py","lineNumber":66,"sourceCode":"\n\ndef create_run_id(meta) -> str:\n    return f\"wf_{meta['name']}_{secrets.token_hex(8)}\"\n\n\ndef reserve_run_id(meta) -> str:\n    \"\"\"Reserve a fresh run identity before any journal can be truncated.\"\"\"\n    STORE.mkdir(parents=True, exist_ok=True)\n    for _ in range(32):\n        run_id = validate_run_id(create_run_id(meta))\n        snapshot_path = STORE / f\"{run_id}.json\"\n        try:\n            fd = os.open(snapshot_path, os.O_CREAT | os.O_EXCL | os.O_WRONLY, 0o600)\n        except FileExistsError:\n            continue\n        os.close(fd)\n        return run_id\n    raise WorkflowInputError(\"could not allocate a unique workflow runId\")\n\n\ndef create_task_id(run_id) -> str:\n    return f\"local_workflow_{run_id}\"\n\n\ndef validate_run_id(run_id):\n    if not isinstance(run_id, str) or not RUN_ID_RE.fullmatch(run_id):\n        raise WorkflowInputError(\"invalid workflow runId\")\n    return run_id\n\n\n# -- Errors --\nclass WorkflowInputError(Exception):\n    \"\"\"Bad workflow, metadata, or schema input.\"\"\"\n\n\n_run_locks_guard = threading.Lock()","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/shareAI-lab/learn-claude-code/blob/985456f4adea6f4df8fbad4112245dbd97444eae/s16_workflow_runtime/code.py#L48-L84","documentation":"reserve_run_id tries up to 32 times to create <runId>.json with O_CREAT|O_EXCL (atomic create-if-absent). Every attempt collided with an existing file, so no unique identity could be reserved and WorkflowInputError is raised before any journal is touched. Run ids embed 16 random hex characters (secrets.token_hex(8)), so 32 straight collisions indicate the filesystem or id generation is degenerate rather than bad luck.","triggerScenarios":"A monkeypatched or seeded secrets.token_hex in tests returning constant values. A STORE directory pre-populated with files matching wf_<name>_<hex>.json for the exact hex values generated (e.g. replaying a captured id sequence). Filesystem issues where O_EXCL is unsupported and open always reports EEXIST.","commonSituations":"Test suites that stub randomness without uniqueness. Restoring a store from a snapshot and rerunning with a deterministic RNG. Exotic network filesystems with broken O_EXCL semantics.","solutions":["If tests stub secrets.token_hex, ensure the stub yields distinct values per call","Point STORE at a clean writable directory for the run","Clear stale <runId>.json placeholder files if a previous run crashed between reservation and journal write"],"exampleFix":"# before (test stub breaks uniqueness)\nmonkeypatch.setattr(secrets, \"token_hex\", lambda n: \"deadbeefdeadbeef\")\n\n# after\nvalues = iter([\"aa11\" * 4, \"bb22\" * 4])\nmonkeypatch.setattr(secrets, \"token_hex\", lambda n: next(values))","handlingStrategy":"retry","validationCode":"from pathlib import Path\n\ndef store_is_clean(store: Path) -> bool:\n    # placeholder collisions are the only realistic failure; ensure the dir is writable\n    return store.is_dir() or store.parent.is_dir()\n\nassert store_is_clean(STORE)","typeGuard":null,"tryCatchPattern":"for attempt in range(3):\n    try:\n        run_id = reserve_run_id(meta)\n        break\n    except WorkflowInputError:\n        if attempt == 2:\n            raise\n        # deterministic-id test stub or polluted store; fix the source, then retry","preventionTips":["Never stub secrets.token_hex with a constant in tests","Keep STORE clean of stale placeholder .json files","Treat 32-collision failure as an environment defect, not bad luck"],"tags":["workflow","run-id","filesystem","uniqueness"],"backgroundTag":null,"analyzedSha":"985456f4adea6f4df8fbad4112245dbd97444eae","analyzedAt":"2026-08-14T22:02:26.028Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}