{"record":{"id":"50819378a0681897","repo":"windmill-labs/windmill","slug":"wac-step-key-requested-key-is-already-used-in","errorCode":null,"errorMessage":"WAC step key \"{requested_key}\" is already used in this workflow. Give each wait_for_approval() its own key so get_approval_urls() can address it.","messagePattern":"WAC step key \"(.+?)\" is already used in this workflow\\. Give each wait_for_approval\\(\\) its own key so get_approval_urls\\(\\) can address it\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"python-client/wmill/wmill/client.py","lineNumber":2996,"sourceCode":"        )\n\n    async def _wait_for_approval(\n        self,\n        timeout: int = 1800,\n        form: dict | None = None,\n        self_approval: bool = True,\n        key: str | None = None,\n    ):\n        if key is not None:\n            _assert_usable_step_key(key, \"wait_for_approval key\")\n        requested_key, key = key, self._alloc_key(key or \"approval\")\n\n        # An explicit key is an identifier callers mint URLs against, so silently\n        # renaming a duplicate to ``<key>_2`` would hand them a URL for the *first*\n        # step — which then fails with \"resume request already sent\" and parks the\n        # workflow until timeout. Unnamed approvals keep auto-numbering.\n        if requested_key and key != requested_key:\n            raise RuntimeError(\n                f'WAC step key \"{requested_key}\" is already used in this workflow. '\n                \"Give each wait_for_approval() its own key so get_approval_urls() can address it.\"\n            )\n\n        if key in self._completed:\n            return self._completed[key]\n\n        if self._executing_key is not None:\n            await _asyncio.Future()\n\n        print(f\"\\n--- WAC: wait_for_approval({key}) ---\")\n        raise _StepSuspend({\n            \"mode\": \"approval\",\n            \"key\": key,\n            \"timeout\": timeout,\n            \"form\": form,\n            \"self_approval_disabled\": not self_approval,\n            \"steps\": [],","sourceCodeStart":2978,"sourceCodeEnd":3014,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/python-client/wmill/wmill/client.py#L2978-L3014","documentation":"In WAC (workflow-as-code) runs each wait_for_approval must have a unique explicit key because get_approval_urls mints URLs addressed by that key. On a duplicate explicit key the library refuses to silently rename it to <key>_2 — that would hand the caller a URL for the first step, which then fails with 'resume request already sent' and parks the workflow until timeout — and raises this RuntimeError instead.","triggerScenarios":"Calling wait_for_approval with the same explicit key twice in one WAC workflow, typically in a loop with a fixed key literal or copy-pasted approval steps.","commonSituations":"Loop-based approvals where the loop index was not interpolated into the key; duplicated approval steps after refactoring; reused template code without renaming the key.","solutions":["Give each call a unique explicit key, e.g. f\"approval-{i}\" in loops","Omit the key on later approvals to get automatic numbering","Search the workflow for duplicated key= arguments to wait_for_approval","Thread a unique suffix parameter through shared approval helpers"],"exampleFix":"// before\nfor i, approver in enumerate(approvers):\n    await client.wait_for_approval(approvers=[approver], key=\"approval\")\n// after\nfor i, approver in enumerate(approvers):\n    await client.wait_for_approval(approvers=[approver], key=f\"approval-{i}\")","handlingStrategy":"try-catch","validationCode":"seen = set()\ndef unique_key(k: str, seen: set) -> str:\n    if k in seen:\n        raise ValueError(f\"duplicate WAC step key {k!r}\")\n    seen.add(k)\n    return k","typeGuard":null,"tryCatchPattern":"key_counts = {}\nkey_counts[k] = key_counts.get(k, 0) + 1\nif key_counts[k] > 1:\n    k = f\"{k}-{key_counts[k]}\"  # pre-deduplicate instead of hitting the error","preventionTips":["Always interpolate a unique component (index/id) into explicit keys in loops","Keep a registry of used keys and assert uniqueness before each call","Omit explicit keys when auto-numbering suffices","Grep workflows for repeated key= literals before deploying"],"tags":["approval","wac","duplicate-key","flow"],"backgroundTag":"duplicate-identifier","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}