{"record":{"id":"8287e5207089242c","repo":"dotnet/aspnetcore","slug":"unknown-action","errorCode":null,"errorMessage":"Unknown action: ","messagePattern":"Unknown action: ","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/Identity/samples/IdentitySample.PasskeyUI/wwwroot/app.js","lineNumber":87,"sourceCode":"            abortController?.abort();\n            abortController = new AbortController();\n            return await navigator.credentials.get({\n                publicKey: options,\n                mediation: useConditionalMediation ? 'conditional' : undefined,\n                signal: abortController.signal,\n            });\n        }\n\n        async function fetchAndSubmitCredential(action, useConditionalMediation = false) {\n            try {\n                const username = new FormData(form).get('username');\n                let credential;\n                if (action === 'register') {\n                    credential = await fetchNewCredential(username);\n                } else if (action === 'authenticate') {\n                    credential = await fetchExistingCredential(username, useConditionalMediation);\n                } else {\n                    throw new Error('Unknown action: ' + action);\n                }\n                var credentialJson = JSON.stringify(credential);\n                form.addEventListener('formdata', (e) => {\n                    e.formData.append('action', action);\n                    e.formData.append('credential', credentialJson);\n                }, { once: true });\n                form.submit();\n            } catch (error) {\n                // Ignore abort errors, they are expected when the user cancels the operation.\n                if (error.name !== 'AbortError') {\n                    statusMessage.textContent = 'Error: ' + error.message;\n                    throw error;\n                }\n            }\n        }\n\n        form.addEventListener('submit', (e) => {\n            if (e.submitter?.name == 'action') {","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/294cab2f9b2e03af6b953820c7ab497c3c8b7ad9/src/Identity/samples/IdentitySample.PasskeyUI/wwwroot/app.js#L69-L105","documentation":"Thrown by fetchAndSubmitCredential() in the sample PasskeyUI app.js (line 87) when the submitter's action value is neither 'register' nor 'authenticate'. The function dispatches on the action string to decide whether to create a new credential or get an existing one; any other value falls into the else branch and throws 'Unknown action: <action>'.","triggerScenarios":"A submit button inside the auth form has name=\"action\" but a value other than 'register' or 'authenticate' (e.g., a stray submit button like 'Cancel' with name=action). Or the form's submitter.name=='action' check matches an unrelated button.","commonSituations":"Adding extra submit buttons to the form (Cancel, Reset, secondary actions) that also carry name=\"action\". Copying the sample and renaming button values without updating the dispatch. A button value with different casing ('Register' vs 'register'). A submit triggered by pressing Enter where the submitter is an unexpected button.","solutions":["Ensure only the register/authenticate buttons use name=\"action\" with values exactly 'register' and 'authenticate'; give other buttons a different name or type=\"button\".","If you add new actions, extend the if/else chain in fetchAndSubmitCredential to handle them.","Verify button values are lowercase and match the dispatch exactly.","Set formnovalidate/type=\"button\" on non-action submits so they do not trigger the handler."],"exampleFix":"// before\n<button name=\"action\" value=\"Save\">Save</button> <!-- triggers Unknown action -->\n\n// after\n<button type=\"button\" onclick=\"...\">Save</button>\n<button name=\"action\" value=\"register\">Register</button>\n<button name=\"action\" value=\"authenticate\">Sign in</button>","handlingStrategy":"validation","validationCode":"const KNOWN_ACTIONS = new Set(['register', 'authenticate']);\nfunction isKnownAction(action: string): boolean {\n  return KNOWN_ACTIONS.has(action);\n}","typeGuard":"type AuthAction = 'register' | 'authenticate';\nfunction isAuthAction(v: unknown): v is AuthAction {\n  return v === 'register' || v === 'authenticate';\n}","tryCatchPattern":null,"preventionTips":["Only register/authenticate buttons should carry name=\"action\".","Use type=\"button\" for non-submit buttons in the form.","Extend the dispatch when adding new actions.","Keep button values lowercase and exact."],"tags":["webauthn","passkey","identity","forms","sample","validation"],"analyzedSha":"294cab2f9b2e03af6b953820c7ab497c3c8b7ad9","analyzedAt":"2026-08-06T20:08:02.189Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}