abhigyanpatwari/GitNexus · error · BadRequestError

Uploaded folder has no usable name

Error message

Uploaded folder has no usable name

What it means

After multipart ingestion, the handler derives a filesystem-safe name from the upload's top-level folder via deriveUploadName, which sanitizes and returns null when the result is 'unknown', '.', '..', or starts with '.'. A null result becomes BadRequestError 400 'Uploaded folder has no usable name' — by design, so un-nameable folders are rejected instead of everyone colliding on UPLOAD_ROOT/unknown.

Source

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

    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);
      if (!baseName) {
        throw new BadRequestError('Uploaded folder has no usable name');
      }

      // webkitRelativePath prefixes every entry with the picked folder, so the
      // real repo root is stageRoot/<topLevelName>. Validate it is a directory
      // BEFORE taking the single analysis slot — a malformed (non-folder)
      // upload must not be able to occupy the slot.
      const innerRoot = path.join(result.stageRoot, result.topLevelName);
      let innerIsDir = false;
      try {
        innerIsDir = (await fsp.stat(innerRoot)).isDirectory();
      } catch {
        innerIsDir = false;
      }
      if (!innerIsDir) {
        throw new BadRequestError('Upload must be a folder');
      }

      const finalName = await pickAvailableName(baseName);

View on GitHub (pinned to aac7515d2a)

Solutions

  1. Rename the folder to alphanumerics plus . _ - before uploading
  2. Avoid a leading dot in the folder name
  3. If the name contains spaces/unicode, transliterate or simplify it first

Example fix

# before
folder name: '.hidden-config' -> 400 Uploaded folder has no usable name

# after
folder name: 'hidden-config' -> accepted
Defensive patterns

Strategy: validation

Validate before calling

const SAFE = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
function hasUsableFolderName(name) { return SAFE.test(name); }
// run before building the FormData
if (!hasUsableFolderName(topLevelName)) alertUser('Rename the folder to letters/numbers/._- without a leading dot');

Type guard

function isUploadableFolderName(name) {
  return typeof name === 'string' && name.length > 0 && !name.startsWith('.') && /^[a-zA-Z0-9._-]+$/.test(name) && name !== 'unknown';
}

Try / catch

try { await fetch('/api/analyze/upload', { method: 'POST', body: formData }); }
catch (e) {
  if (e.status === 400 && /no usable name/.test(e.message)) promptUserToRenameFolder();
  else throw e;
}

Prevention

When it happens

Trigger: POST /api/analyze/upload where the picked folder's name contains no characters from the safe set [A-Za-z0-9._-] after sanitization (e.g. '===', '***', emoji-only, whitespace-only), or is a dot-folder like '.config'.

Common situations: Uploading hidden/dot-prefixed directories from OS tools; folders named entirely in scripts/unicode that sanitizeRepoName strips to the 'unknown' sentinel; unusual browser-picker folder names.

Related errors


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