{"record":{"id":"13bdf5322c5d5e15","repo":"eyaltoledano/claude-task-master","slug":"mfa-verification-failed","errorCode":"MFA_VERIFICATION_FAILED","errorMessage":"MFA challenge information missing","messagePattern":"MFA challenge information missing","errorType":"error_code","errorClass":"AuthenticationError","httpStatus":null,"severity":"error","filePath":"apps/cli/src/commands/auth.command.ts","lineNumber":520,"sourceCode":"\t */\n\tprivate async authenticateWithToken(token: string): Promise<AuthCredentials> {\n\t\tconst spinner = ora('Verifying authentication token...').start();\n\n\t\ttry {\n\t\t\tconst credentials = await this.authManager.authenticateWithCode(token);\n\t\t\tspinner.succeed('Successfully authenticated!');\n\t\t\treturn credentials;\n\t\t} catch (error) {\n\t\t\t// Check if MFA is required BEFORE showing failure message\n\t\t\tif (\n\t\t\t\terror instanceof AuthenticationError &&\n\t\t\t\terror.code === 'MFA_REQUIRED'\n\t\t\t) {\n\t\t\t\t// Stop spinner without showing failure - MFA is required, not a failure\n\t\t\t\tspinner.stop();\n\n\t\t\t\tif (!error.mfaChallenge?.factorId) {\n\t\t\t\t\tthrow new AuthenticationError(\n\t\t\t\t\t\t'MFA challenge information missing',\n\t\t\t\t\t\t'MFA_VERIFICATION_FAILED'\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// Use shared MFA flow handler\n\t\t\t\treturn this.handleMFAVerification(error);\n\t\t\t}\n\n\t\t\t// Only show \"Authentication failed\" for actual failures\n\t\t\tspinner.fail('Authentication failed');\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t/**\n\t * Handle MFA verification flow\n\t * Uses shared MFA utilities from auth-ui.ts","sourceCodeStart":502,"sourceCodeEnd":538,"githubUrl":"https://github.com/eyaltoledano/claude-task-master/blob/c0c98d367c55296bfe69e65680625b6db437af02/apps/cli/src/commands/auth.command.ts#L502-L538","documentation":"copyTag validates the target tag name against /^[a-zA-Z0-9_-]+$/ before copying tasks from a source tag. If the targetName contains any other characters (spaces, slashes, dots, unicode), this error is thrown to keep tag names valid as keys in the tagged tasks data structure. It is a pre-write guard so invalid tags never enter tasks.json.","triggerScenarios":"Calling copyTag (or `task-master copy-tag`) with a target name containing whitespace, slashes (e.g. 'feature/x'), dots, or other non [a-zA-Z0-9_-] characters, or an empty/undefined targetName.","commonSituations":"Deriving a tag name from a branch name like 'feature/login-flow' or a version string 'v1.2' without sanitizing; passing a user-supplied tag from a UI or script with spaces.","solutions":["Remove or replace invalid characters in the target name (replace [^a-zA-Z0-9_-] with '-')","Use sanitizeBranchNameForTag() (or equivalent sanitization) before calling copyTag","Keep tag names lowercase alphanum with hyphens/underscores only"],"exampleFix":"// before\nawait copyTag(tasksPath, 'backlog', 'feature/new-ui');\n// after\nawait copyTag(tasksPath, 'backlog', 'feature-new-ui');","handlingStrategy":"validation","validationCode":"function isValidTagName(name){return typeof name==='string' && /^[a-zA-Z0-9_-]+$/.test(name);}\nif (!isValidTagName(targetName)) throw new Error('Invalid target tag name: '+targetName);","typeGuard":"const isTagName = (v: unknown): v is string => typeof v === 'string' && /^[a-zA-Z0-9_-]+$/.test(v);","tryCatchPattern":"try {\n  await copyTag(tasksPath, source, target);\n} catch (e) {\n  if (e.message.includes('can only contain')) {\n    const sanitized = target.replace(/[^a-zA-Z0-9_-]/g, '-');\n    return copyTag(tasksPath, source, sanitized);\n  }\n  throw e;\n}","preventionTips":["Sanitize tag names derived from branch names or versions before use","Reject invalid tag input at the UI/script boundary","Keep a shared isTagName() helper instead of ad-hoc regexes"],"tags":["validation","cli","tag-management"],"backgroundTag":"invalid-tag-name","analyzedSha":"c0c98d367c55296bfe69e65680625b6db437af02","analyzedAt":"2026-08-29T02:56:26.071Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}