{"record":{"id":"a65359d36c198a3f","repo":"abhigyanpatwari/GitNexus","slug":"invalid-group-name-name-names-must-start-wit","errorCode":null,"errorMessage":"Invalid group name \"${name}\". Names must start with a letter or digit and contain only [a-zA-Z0-9_-].","messagePattern":"Invalid group name \"(.+?)\"\\. Names must start with a letter or digit and contain only \\[a-zA-Z0-9_-\\]\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gitnexus/src/core/group/storage.ts","lineNumber":22,"sourceCode":"import type { ContractRegistry } from './types.js';\nimport { writeFileAtomic } from '../../storage/fs-atomic.js';\nimport { getGlobalDir } from '../../storage/global-dir.js';\n\nexport const CONTRACTS_FILE = 'contracts.json';\n\nexport function getDefaultGitnexusDir(): string {\n  return getGlobalDir();\n}\n\nexport function getGroupsBaseDir(gitnexusDir?: string): string {\n  return path.join(gitnexusDir || getDefaultGitnexusDir(), 'groups');\n}\n\nconst GROUP_NAME_RE = /^[a-zA-Z0-9][a-zA-Z0-9_-]*$/;\n\nexport function validateGroupName(name: string): void {\n  if (!GROUP_NAME_RE.test(name)) {\n    throw new Error(\n      `Invalid group name \"${name}\". Names must start with a letter or digit and contain only [a-zA-Z0-9_-].`,\n    );\n  }\n}\n\nexport function getGroupDir(gitnexusDir: string, groupName: string): string {\n  validateGroupName(groupName);\n  return path.join(gitnexusDir, 'groups', groupName);\n}\n\n/** The registry path, so callers that stat or watch the file do not respell its name. */\nexport function getContractRegistryPath(groupDir: string): string {\n  return path.join(groupDir, CONTRACTS_FILE);\n}\n\nexport async function writeContractRegistry(\n  groupDir: string,\n  registry: ContractRegistry,","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/0d1aed942f0e8b5d3bac27519fff441aceea722d/gitnexus/src/core/group/storage.ts#L4-L40","documentation":"Thrown by validateGroupName() in gitnexus/src/core/group/storage.ts before any group directory path is built. A group name must match /^[a-zA-Z0-9][a-zA-Z0-9_-]*$/ — start with a letter or digit, then only letters, digits, underscore, or hyphen. The guard exists because the name is joined directly into a filesystem path (getGroupDir), so anything else (spaces, slashes, dots, leading dash) is rejected to prevent malformed or traversing paths.","triggerScenarios":"Calling a group command (e.g. `gitnexus group create` or any API that goes through getGroupDir/createGroupDir) with a name like \"my repo\" (space), \"../evil\" or \"org/team\" (slash), \"@org/team\" (@), \".hidden\" or \"-flag\" (leading non-alphanumeric), or a name containing dots, colons, or unicode characters.","commonSituations":"Scripting group creation from raw repository or workspace names that contain spaces or slashes; passing npm-style scoped names; a shell variable that picked up a leading dash or trailing whitespace; names copied from URLs.","solutions":["Rename the group to match [a-zA-Z0-9][a-zA-Z0-9_-]* (e.g. \"my repo\" -> \"my-repo\", \"org/team\" -> \"org-team\")","Trim whitespace and strip/replace disallowed characters (slash, dot, @, spaces) in the script that generates the name","If the name came from a repo path, use only the final path segment and sanitize it before passing it to the group command"],"exampleFix":"# before\n$ gitnexus group create \"@org/my team\"\n# after\n$ gitnexus group create \"org-my-team\"","handlingStrategy":"validation","validationCode":"const GROUP_NAME_RE = /^[a-zA-Z0-9][a-zA-Z0-9_-]*$/;\nconst name = rawInput.trim().replace(/[/@.]+/g, '-').replace(/-+/g, '-');\nif (!GROUP_NAME_RE.test(name)) {\n  throw new TypeError(`Refusing to create group: \"${rawInput}\" sanitizes to invalid name \"${name}\"`);\n}\nawait createGroupDir(gitnexusDir, name, force);","typeGuard":"function isValidGroupName(name: unknown): name is string {\n  return typeof name === 'string' && /^[a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(name);\n}","tryCatchPattern":"try {\n  await createGroupDir(gitnexusDir, name);\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith('Invalid group name')) {\n    // surface a friendly prompt for a corrected name; do not retry the same input\n  }\n  throw err;\n}","preventionTips":["Generate group names from a sanitize helper that trims and replaces disallowed characters before any group API call","In CLIs, validate the name before touching the filesystem so users get input feedback, not a stack trace","Never build group names from raw user input, repo URLs, or paths without normalization"],"tags":["validation","groups","filesystem","path-safety","naming"],"backgroundTag":"invalid-identifier","analyzedSha":"0d1aed942f0e8b5d3bac27519fff441aceea722d","analyzedAt":"2026-08-20T23:29:22.980Z","contentChangedAt":"2026-08-20T23:29:22.980Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}