{"record":{"id":"0d5222c86ad7fda7","repo":"eyaltoledano/claude-task-master","slug":"invalid-conventional-commit-format","errorCode":null,"errorMessage":"Invalid conventional commit format","messagePattern":"Invalid conventional commit format","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/tm-core/src/modules/git/services/commit-message-generator.ts","lineNumber":168,"sourceCode":"\t\treturn {\n\t\t\tisValid: errors.length === 0,\n\t\t\terrors\n\t\t};\n\t}\n\n\t/**\n\t * Parse a conventional commit message into its components\n\t */\n\tparseCommitMessage(message: string): ParsedCommitMessage {\n\t\tconst lines = message.split('\\n');\n\t\tconst header = lines[0];\n\n\t\t// Parse header: type(scope)!: description\n\t\tconst headerRegex = /^(\\w+)(?:\\(([^)]+)\\))?(!)?:\\s*(.+)$/;\n\t\tconst match = header.match(headerRegex);\n\n\t\tif (!match) {\n\t\t\tthrow new Error('Invalid conventional commit format');\n\t\t}\n\n\t\tconst [, type, scope, breaking, description] = match;\n\n\t\t// Body is everything after the first blank line\n\t\tconst bodyStartIndex = lines.findIndex((line, i) => i > 0 && line === '');\n\t\tconst body =\n\t\t\tbodyStartIndex !== -1\n\t\t\t\t? lines\n\t\t\t\t\t\t.slice(bodyStartIndex + 1)\n\t\t\t\t\t\t.join('\\n')\n\t\t\t\t\t\t.trim()\n\t\t\t\t: undefined;\n\n\t\treturn {\n\t\t\ttype,\n\t\t\tscope,\n\t\t\tbreaking: breaking === '!',","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/eyaltoledano/claude-task-master/blob/c0c98d367c55296bfe69e65680625b6db437af02/packages/tm-core/src/modules/git/services/commit-message-generator.ts#L150-L186","documentation":"parseCommitMessage in CommitMessageGenerator throws this when a commit message header does not match the Conventional Commits pattern type(scope)!: description (e.g. 'feat: add login'). The regex requires a word-char type, optional parenthesized scope, optional bang, a colon, and a non-empty description.","triggerScenarios":"Calling the parsed getter / parseCommitMessage() with a message whose first line lacks 'type: description' form: no colon, empty description, multi-line-first-line text, or a type containing non-word characters (e.g. 'chore(deps):' is fine, but 'fixed things' is not).","commonSituations":"Hand-written commit messages that don't follow Conventional Commits, merge commit defaults like \"Merge branch 'x'\", messages that only contain a body, or locale/typo issues like a missing space after the colon is actually fine but 'feat - x' is not.","solutions":["Rewrite the first line as '<type>[optional scope][!]: <description>', e.g. 'feat(auth): add PKCE login'","Use a supported type: feat, fix, chore, docs, refactor, test, etc.","If parsing arbitrary messages, catch this error and treat the message as non-conventional"],"exampleFix":"// before\ngenerator.parse('updated stuff'); // throws\n// after\ngenerator.parse('chore: updated stuff');","handlingStrategy":"validation","validationCode":"const headerRegex = /^(\\w+)(?:\\(([^)]+)\\))?(!)?:\\s*(.+)$/;\nif (!headerRegex.test(commitMessage.split('\\n')[0])) {\n  // reject or fix message before calling parse\n}","typeGuard":"function isConventionalMessage(msg: string): boolean {\n  return /^(\\w+)(\\([^)]+\\))?(!)?:\\s+.+$/.test(msg.split('\\n')[0]);\n}","tryCatchPattern":"try {\n  const parsed = generator.parsed;\n} catch (e) {\n  if ((e as Error).message === 'Invalid conventional commit format') {\n    // fall back to raw message or prompt for a compliant message\n  }\n}","preventionTips":["Use commitlint or a commit template to enforce Conventional Commits","Adopt commitizen/husky to generate compliant messages interactively","Never feed merge-commit defaults into the parser"],"tags":["git","conventional-commits","parsing"],"backgroundTag":"conventional-commit-format-invalid","analyzedSha":"c0c98d367c55296bfe69e65680625b6db437af02","analyzedAt":"2026-08-29T02:56:26.071Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}