{"record":{"id":"961f1f31dacd067f","repo":"AUTOMATIC1111/stable-diffusion-webui","slug":"cannot-have-a-selectable-script-in-the-always-on-s","errorCode":null,"errorMessage":"Cannot have a selectable script in the always on scripts params","messagePattern":"Cannot have a selectable script in the always on scripts params","errorType":"http","errorClass":"HTTPException","httpStatus":422,"severity":"error","filePath":"modules/api/api.py","lineNumber":355,"sourceCode":"\n        if input_script_args is not None:\n            for index, value in input_script_args.items():\n                script_args[index] = value\n\n        # position 0 in script_arg is the idx+1 of the selectable script that is going to be run when using scripts.scripts_*2img.run()\n        if selectable_scripts:\n            script_args[selectable_scripts.args_from:selectable_scripts.args_to] = request.script_args\n            script_args[0] = selectable_idx + 1\n\n        # Now check for always on scripts\n        if request.alwayson_scripts:\n            for alwayson_script_name in request.alwayson_scripts.keys():\n                alwayson_script = self.get_script(alwayson_script_name, script_runner)\n                if alwayson_script is None:\n                    raise HTTPException(status_code=422, detail=f\"always on script {alwayson_script_name} not found\")\n                # Selectable script in always on script param check\n                if alwayson_script.alwayson is False:\n                    raise HTTPException(status_code=422, detail=\"Cannot have a selectable script in the always on scripts params\")\n                # always on script with no arg should always run so you don't really need to add them to the requests\n                if \"args\" in request.alwayson_scripts[alwayson_script_name]:\n                    # min between arg length in scriptrunner and arg length in the request\n                    for idx in range(0, min((alwayson_script.args_to - alwayson_script.args_from), len(request.alwayson_scripts[alwayson_script_name][\"args\"]))):\n                        script_args[alwayson_script.args_from + idx] = request.alwayson_scripts[alwayson_script_name][\"args\"][idx]\n        return script_args\n\n    def apply_infotext(self, request, tabname, *, script_runner=None, mentioned_script_args=None):\n        \"\"\"Processes `infotext` field from the `request`, and sets other fields of the `request` according to what's in infotext.\n\n        If request already has a field set, and that field is encountered in infotext too, the value from infotext is ignored.\n\n        Additionally, fills `mentioned_script_args` dict with index: value pairs for script arguments read from infotext.\n        \"\"\"\n\n        if not request.infotext:\n            return {}\n","sourceCodeStart":337,"sourceCodeEnd":373,"githubUrl":"https://github.com/AUTOMATIC1111/stable-diffusion-webui/blob/82a973c04367123ae98bd9abdf80d9eda9b910e2/modules/api/api.py#L337-L373","documentation":"HTTP 422 raised in initscript_args when a script resolved from request.alwayson_scripts has alwayson == False, i.e. it is a selectable script (appears in the Scripts dropdown) rather than an always-on one. The API enforces the split: selectable scripts go through script_name/script_args, always-on ones through alwayson_scripts, and mixing them is rejected.","triggerScenarios":"POST /sdapi/v1/txt2img with {\"alwayson_scripts\": {\"X/Y/Z plot\": {...}}} (or any other dropdown script like Prompt matrix); the script exists and is found, but its alwayson flag is False because it was registered as selectable.","commonSituations":"Clients migrating from script_name usage trying to force-run dropdown scripts always-on; authors of custom extension scripts who forgot to set self.alwayson = True in the script class; script category changes between versions.","solutions":["Pass selectable scripts via the top-level script_name + script_args fields instead of alwayson_scripts","If you own the script, set self.alwayson = True (and a name) in its Script class so it qualifies as always-on","Pick a genuinely always-on script (e.g. controlnet-style extension scripts) for the alwayson_scripts map"],"exampleFix":"# before\njson={'alwayson_scripts':{'X/Y/Z plot':{'args':[]}}}\n\n# after\njson={'script_name':'X/Y/Z plot','script_args':[...]}\n\n# extension authors:\n# class Script(scripts.Script):\n#     def __init__(self):\n#         self.alwayson = True","handlingStrategy":"validation","validationCode":"selectable = set(scripts_api['txt2img']) | set(scripts_api['img2img'])\nfor name in payload.get('alwayson_scripts', {}):\n    if name in selectable:\n        payload['script_name'] = name\n        payload['script_args'] = payload['alwayson_scripts'].pop(name).get('args', [])","typeGuard":"def is_selectable_script(name: str, selectable: set[str]) -> bool:\n    return name in selectable","tryCatchPattern":"if resp.status_code == 422 and 'selectable script in the always on' in resp.json()['detail']:\n    move_selectable_scripts_out_of_alwayson(payload)\n    resp = requests.post(url, json=payload, auth=auth)","preventionTips":["Route dropdown scripts through script_name/script_args only","Extension authors: set self.alwayson = True for scripts meant to be always-on","Test payloads against /sdapi/v1/scripts metadata in CI"],"tags":["api","scripts","http-422","validation","stable-diffusion-webui"],"backgroundTag":null,"analyzedSha":"82a973c04367123ae98bd9abdf80d9eda9b910e2","analyzedAt":"2026-08-14T16:46:43.225Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}