{"record":{"id":"3408d725bd0c0fff","repo":"abhigyanpatwari/GitNexus","slug":"source-branch-name-must-not-contain-whitespace","errorCode":null,"errorMessage":"${source}: branch name must not contain whitespace.","messagePattern":"(.+?): branch name must not contain whitespace\\.","errorType":"validation","errorClass":"GitNexusRcError","httpStatus":null,"severity":"warning","filePath":"gitnexus/src/cli/analyze-config.ts","lineNumber":173,"sourceCode":"  }\n};\n\n/**\n * Validate a user-supplied branch name (from CLI or `.gitnexusrc`). Returns the\n * trimmed name or throws {@link GitNexusRcError}. Conservative but accepts the\n * shapes real branches use (`feature/foo-bar`, `release/1.2`, `develop`).\n */\nexport function validateBranchName(value: string, source: string): string {\n  const trimmed = value.trim();\n  if (!trimmed) {\n    throw new GitNexusRcError(`${source}: branch name must not be empty.`);\n  }\n  if (trimmed.length > BRANCH_MAX_LENGTH) {\n    throw new GitNexusRcError(`${source}: branch name is too long (max ${BRANCH_MAX_LENGTH}).`);\n  }\n  assertNoHiddenChars(trimmed, source);\n  if (/\\s/.test(trimmed)) {\n    throw new GitNexusRcError(`${source}: branch name must not contain whitespace.`);\n  }\n  // git ref-name rules (subset): reject characters git itself forbids in refs.\n  if (/[~^:?*[\\\\]/.test(trimmed)) {\n    throw new GitNexusRcError(\n      `${source}: branch name contains characters not allowed in a git ref (~ ^ : ? * [ \\\\).`,\n    );\n  }\n  if (trimmed.startsWith('-')) {\n    throw new GitNexusRcError(`${source}: branch name must not start with \"-\".`);\n  }\n  if (trimmed.includes('..')) {\n    throw new GitNexusRcError(`${source}: branch name must not contain \"..\".`);\n  }\n  // Git permits a backtick in a ref, but the branch is embedded inside a\n  // Markdown inline-code span in the generated AGENTS.md/CLAUDE.md regression\n  // example, where a backtick would close the span early and let the rest of\n  // the template render as instruction text. Reject it at this single\n  // chokepoint so all three tiers (CLI flag, .gitnexusrc, auto-detect via","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/52924ef12c2290ceee4612526a828ec4cdf2047f/gitnexus/src/cli/analyze-config.ts#L155-L191","documentation":"On Windows, libuv resolves db.close() before the kernel releases the file handle; a subsequent new Database(samePath) can race the release. The post-close probe (HANDLE_RELEASE_PROBE_ATTEMPTS=5 × HANDLE_RELEASE_PROBE_DELAY_MS=50 ≈ 250ms budget) forces residual locks to surface so open-time retry absorbs the lag. This warn means the probe budget was exhausted with a lock code still in flight — most often antivirus (Windows Defender) holding the file past 250ms.","triggerScenarios":"process.platform === 'win32' and waitForWindowsHandleRelease(closingDbPath) returns false after the retry budget — close immediately followed by reopen of the same DB path in one process, with Defender/AV scanning the storage directory and extending handle release beyond the probe window.","commonSituations":"Real-time AV scanning of the GitNexus storage directory; tight close-then-reopen cycles during tests or repeated analyze runs; file-system filter drivers (indexers, sync clients like OneDrive/Dropbox) holding the handle.","solutions":["Add an antivirus/Defender exclusion for the GitNexus storage directory — the message's own recommendation","Retry the operation: the next openLbugConnection still absorbs residual lag via its open-time retry, so a transient occurrence is safe","Pause sync/indexing tools (OneDrive, search indexer) over the storage directory","If it repeats on every close/reopen despite exclusions, increase the gap between close and reopen in the calling code"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"import { open } from 'node:fs/promises';\n// Windows: probe handle availability before re-opening the same DB path\nif (process.platform === 'win32') {\n  let h: Awaited<ReturnType<typeof open>> | undefined;\n  try { h = await open(dbPath, 'r+'); } finally { await h?.close(); }\n}","typeGuard":"const isWindowsLockErrno = (e: unknown): boolean => {\n  const code = (e as NodeJS.ErrnoException | null)?.code;\n  return code === 'EBUSY' || code === 'EPERM' || code === 'EACCES';\n};","tryCatchPattern":"try {\n  await openLbugConnection(dbPath);\n} catch (e) {\n  if (isWindowsLockErrno(e)) {\n    // residual close lag or AV hold — back off and retry once before failing\n    await new Promise((r) => setTimeout(r, 250));\n    return openLbugConnection(dbPath);\n  }\n  throw e;\n}","preventionTips":["Add a Defender/AV exclusion for the GitNexus storage directory","Pause sync/indexing tools over the storage dir during analyze","Leave a gap between close and reopen of the same DB path in one process"],"tags":["windows","file-lock","antivirus","ladybugdb"],"backgroundTag":"antivirus-file-lock","analyzedSha":"52924ef12c2290ceee4612526a828ec4cdf2047f","analyzedAt":"2026-08-20T23:29:22.980Z","contentChangedAt":"2026-08-20T23:29:22.980Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}