{"record":{"id":"c075d0c6dabf25f9","repo":"abhigyanpatwari/GitNexus","slug":"repository-name-must-use-only-letters-digits","errorCode":null,"errorMessage":"repository name must use only letters, digits, \".\", \"_\", or \"-\" and must not be \"unknown\"","messagePattern":"repository name must use only letters, digits, \"\\.\", \"_\", or \"-\" and must not be \"unknown\"","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"gitnexus/src/core/auto-sync/config.ts","lineNumber":328,"sourceCode":"  ) {\n    throw new Error('path must include owner/repo without traversal');\n  }\n  // The final segment becomes the on-disk clone directory via `extractRepoName`,\n  // whose name rules are stricter than the path check above: a backslash — or\n  // anything outside `[A-Za-z0-9._-]` — passes here and then throws once per\n  // tick inside the sync loop instead of at config load. These rules are a\n  // strict superset, so anything accepted here is accepted there.\n  const lastSegment = pathParts[pathParts.length - 1];\n  const repoName = /\\.git$/i.test(lastSegment) ? lastSegment.slice(0, -4) : lastSegment;\n  if (\n    !repoName ||\n    repoName === '.' ||\n    repoName === '..' ||\n    repoName === 'unknown' ||\n    repoName.startsWith('-') ||\n    !REMOTE_REPO_NAME_PATTERN.test(repoName)\n  ) {\n    throw new Error(\n      'repository name must use only letters, digits, \".\", \"_\", or \"-\" and must not be \"unknown\"',\n    );\n  }\n}\n\nexport function validateAutoSyncBranchName(branch: string): void {\n  if (!branch.trim()) throw new Error('must not be empty');\n  if (/[\\s\\0-\\x1f\\x7f]/.test(branch))\n    throw new Error('must not contain whitespace or control characters');\n  if (/[~^:?*[\\\\]/.test(branch)) throw new Error('contains characters not allowed in a git ref');\n  if (branch.startsWith('-')) throw new Error('must not start with \"-\"');\n  if (branch.startsWith('/')) throw new Error('must not start with \"/\"');\n  if (branch.includes('..')) throw new Error('must not contain \"..\"');\n  if (branch.includes('`')) throw new Error('must not contain backticks');\n  if (branch.endsWith('/') || branch.endsWith('.')) throw new Error('must not end with \"/\" or \".\"');\n  if (branch.includes('//')) throw new Error('must not contain consecutive slashes');\n  if (branch.includes('@{')) throw new Error('must not contain \"@{\"');\n  if (","sourceCodeStart":310,"sourceCodeEnd":346,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/0d1aed942f0e8b5d3bac27519fff441aceea722d/gitnexus/src/core/auto-sync/config.ts#L310-L346","documentation":"The final path segment of the remote URL becomes the on-disk clone directory name, so validateAutoSyncRemoteUrl applies strict name rules: after stripping a trailing .git, the repo name must match REMOTE_REPO_NAME_PATTERN ([A-Za-z0-9._-]) and must not be empty, '.', '..', 'unknown', or start with '-'. This error means the repo name violates those rules. Unlike the looser path check, this is enforced strictly to keep the clone directory safe and predictable.","triggerScenarios":"remote URL whose last segment contains characters like '+', '~', '%', non-ASCII letters, or a backslash (git@github.com:acme/my~repo.git); a repo literally named 'unknown' (git@github.com:acme/unknown.git); a name starting with '-' (git@github.com:acme/-weird.git); or a URL ending in '/' leaving an empty name.","commonSituations":"Repo renamed on the forge to a name with unusual characters; URL truncated so the name is missing; pasting a URL that ends with a slash;placeholder 'unknown' left in generated config by another tool.","solutions":["Rename the repository on the forge to use only letters, digits, '.', '_', and '-'.","Fix the URL so the final segment is the actual repo name with no trailing slash.","Use the repo's .git suffix form (git@github.com:acme/repo.git) — the suffix is stripped before validation.","If the repo is genuinely named 'unknown' or starts with '-', rename it; those exact values are reserved by the library.","Ensure no URL-encoding or shell artifacts (%20, ~) remain in the config value."],"exampleFix":"// before\nremote_url = git@github.com:acme/my repo+tools.git\n// after\nremote_url = git@github.com:acme/my-repo-tools.git","handlingStrategy":"validation","validationCode":"const NAME_RE = /^[A-Za-z0-9._-]+$/;\nfunction repoNameOk(url) {\n  const m = /^git@[^:\\s/]+:(\\S+)$/.exec((url ?? '').trim());\n  if (!m) return false;\n  let last = m[1].split('/').pop();\n  if (/\\.git$/i.test(last)) last = last.slice(0, -4);\n  return !!last && !['.', '..', 'unknown'].includes(last) && !last.startsWith('-') && NAME_RE.test(last);\n}\nif (!repoNameOk(cfg.remote_url)) throw new Error('repo name must match [A-Za-z0-9._-] and not be \"unknown\"');","typeGuard":null,"tryCatchPattern":"try {\n  validateAutoSyncRemoteUrl(remoteUrl);\n} catch (e) {\n  if (String(e.message).includes('repository name must use only')) {\n    log.error(`Repo name from '${remoteUrl}' is not a safe directory name; rename the repo or fix the URL.`);\n  }\n  throw e;\n}","preventionTips":["Keep repo names restricted to letters, digits, '.', '_', '-'.","Avoid renaming repos to values with '+', '~', or unicode characters if auto-sync is used.","Never use 'unknown' as a repo name; it is a reserved sentinel.","Strip trailing slashes and whitespace before saving the URL."],"tags":["config","git","naming","validation"],"backgroundTag":"invalid-identifier-format","analyzedSha":"0d1aed942f0e8b5d3bac27519fff441aceea722d","analyzedAt":"2026-09-08T00:40:44.970Z","contentChangedAt":"2026-09-08T00:40:44.970Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}