abhigyanpatwari/GitNexus · error · BadRequestError

Could not allocate an upload directory after ${MAX_NAME_COLL

Error message

Could not allocate an upload directory after ${MAX_NAME_COLLISION_TRIES} attempts

What it means

pickAvailableName in analyze-upload.ts tries the sanitized upload name and then -2, -3, ... suffixes under UPLOAD_ROOT, up to MAX_NAME_COLLISION_TRIES=100 attempts; if every candidate directory already exists (or getUploadDir rejects the name), it throws BadRequestError 409. It exists to bound the collision scan instead of looping forever.

Source

Thrown at gitnexus/src/server/analyze-upload.ts:61

 * collision with an existing upload. Bounded to avoid an unbounded scan.
 */
async function pickAvailableName(base: string): Promise<string> {
  for (let i = 0; i < MAX_NAME_COLLISION_TRIES; i++) {
    const name = i === 0 ? base : `${base}-${i + 1}`;
    let dir: string;
    try {
      dir = getUploadDir(name);
    } catch {
      continue;
    }
    try {
      await fsp.access(dir);
      // exists → try the next suffix
    } catch {
      return name; // ENOENT → available
    }
  }
  throw new BadRequestError(
    `Could not allocate an upload directory after ${MAX_NAME_COLLISION_TRIES} attempts`,
    409,
  );
}

export function createAnalyzeUploadHandler(deps: AnalyzeUploadDeps) {
  const ingest = deps.ingest ?? ingestUpload;

  return async function handleAnalyzeUploadRequest(req: Request, res: Response): Promise<void> {
    let stageRoot: string | undefined;
    let promotedDir: string | undefined;
    let createdJobId: string | undefined;
    let launched = false;
    try {
      const result = await ingest(req as IncomingMessage);
      stageRoot = result.stageRoot;

      const baseName = deriveUploadName(result.topLevelName);

View on GitHub (pinned to aac7515d2a)

Solutions

  1. Delete or archive old upload directories under the upload root (inside the server's GITNEXUS_HOME data volume) and retry
  2. Rename the top-level folder before uploading so the derived base name differs
  3. Add periodic cleanup that removes upload dirs whose analysis jobs are terminal

Example fix

# before: 101 uploads of 'my-project' exist
rm -rf "$GITNEXUS_HOME"/uploads/my-project*  # or archive them; then re-upload

# after: unique name avoids the collision entirely
mv my-project my-project-run-42 && upload again
Defensive patterns

Strategy: retry

Validate before calling

// client-side: make collisions unlikely before uploading
const uniqueFolderName = `${baseFolderName}-${Date.now().toString(36)}`;
formData.set('name', uniqueFolderName);

Type guard

function willNotCollide(base, existingNames) {
  const candidates = [base, ...Array.from({ length: 100 }, (_, i) => `${base}-${i + 2}`)];
  return candidates.some((c) => !existingNames.includes(c));
}

Try / catch

// server operator: free suffix space, then the caller retries
try { await postUpload(formData); }
catch (e) {
  if (/Could not allocate an upload directory/.test(String(e.message))) {
    await cleanupTerminalUploadDirs(); // rm/archive finished upload dirs under GITNEXUS_HOME uploads
    return postUpload(formData);
  }
  throw e;
}

Prevention

When it happens

Trigger: POST /api/analyze/upload of a folder whose derived name already has 100 suffixed siblings (base, base-2 ... base-101 all present); typically after ~100 uploads of the same-named folder with no cleanup of old upload directories.

Common situations: CI pipelines or classroom/demo setups repeatedly uploading the identically-named folder; an operator never pruning UPLOAD_ROOT under the server's data dir (GITNEXUS_HOME); long-lived self-hosted instances.

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@aac7515d2a (2026-08-20). Data as JSON: /api/errors/9d7a625723f48dd7. Report an issue: GitHub.