abhigyanpatwari/GitNexus · error · BadRequestError
Upload path too long
Error message
Upload path too long
What it means
The length cap in resolveContainedDest: an upload manifest path longer than MAX_PATH_LENGTH (4096 chars) throws 'Upload path too long' before any write. The guard exists because some filesystems silently truncate or error on very long paths, and unbounded lengths are a cheap DoS/vector for the traversal checker; it runs after the type/emptiness check and before the leading-slash check.
Source
Thrown at gitnexus/src/server/upload-ingest.ts:71
stageRoot: string;
fileCount: number;
totalBytes: number;
/** First path segment shared by the uploaded tree (the picked folder). */
topLevelName: string;
}
/**
* Resolve a client-provided relative path to an absolute destination PROVABLY
* contained within `stageRoot`. Throws BadRequestError on any unsafe input.
* This is the load-bearing path-traversal-on-write control; keep it pure and
* unit-tested.
*/
export function resolveContainedDest(stageRoot: string, rel: unknown): string {
if (typeof rel !== 'string' || rel.length === 0) {
throw new BadRequestError('Invalid upload path');
}
if (rel.length > MAX_PATH_LENGTH) {
throw new BadRequestError('Upload path too long');
}
// webkitRelativePath is always relative; a leading slash is absolute/hostile.
if (rel.startsWith('/')) {
throw new BadRequestError('Invalid upload path');
}
// Browsers emit forward slashes only; a NUL byte or backslash is hostile.
if (rel.includes('\u0000') || rel.includes('\\')) {
throw new BadRequestError('Invalid upload path');
}
const rawSegments = rel.split('/').filter((s) => s.length > 0);
if (rawSegments.length === 0 || rawSegments.length > MAX_PATH_DEPTH) {
throw new BadRequestError('Invalid upload path');
}
const segments: string[] = [];
for (const seg of rawSegments) {
// Normalize so NFC/NFD variants don't collide silently on case/unicode
// -folding filesystems (macOS/Windows).
const s = seg.normalize('NFC');View on GitHub (pinned to aac7515d2a)
Solutions
- Fix the client to send the file's genuine webkitRelativePath (it is bounded by OS limits far below 4096)
- Look for cumulative string concatenation bugs in your manifest builder (path growing per level instead of being taken from the File object)
- Treat a 400 'Upload path too long' as evidence of a hostile or broken client — log the offending part's field name, not the path itself
Example fix
// before — cumulative join grows the path each level rel = rel + '/' + part; // may exceed 4096 across deep trees // after — take the browser-provided relative path once rel = file.webkitRelativePath || file.name;
Defensive patterns
Strategy: validation
Validate before calling
const MAX_PATH_LENGTH = 4096; // mirror of the server cap
if (entry.path.length > MAX_PATH_LENGTH) {
throw new Error(`manifest path too long (${entry.path.length} > ${MAX_PATH_LENGTH})`);
} Type guard
function isBoundedUploadPath(rel: string): boolean {
return rel.length > 0 && rel.length <= 4096;
} Prevention
- Take paths from webkitRelativePath once instead of building them by cumulative concatenation
- Enforce a client-side length cap matching the server's 4096 limit
- Log field names (not full paths) when the server rejects an entry, to locate the broken uploader logic
When it happens
Trigger: POST multipart ingest where a manifest webkitRelativePath exceeds 4096 characters — e.g. a fabricated manifest with a padded segment, a client bug concatenating paths cumulatively, or a hostile fuzzing payload probing the limits.
Common situations: Automated/fuzz clients generating pathological manifests; a client that joins folder names repeatedly (path += '/' + dir on each level); deeply nested picks on Windows where paths already approach limits; essentially never from a real browser folder picker, since OS path limits sit well below 4096.
Related errors
- Invalid upload path
- Upload path must not contain traversal segments
- Upload path escapes the sandbox
- Uploaded folder has no usable name
- Upload must be a folder
AI-assisted analysis of abhigyanpatwari/GitNexus@aac7515d2a (2026-08-20).
Data as JSON: /api/errors/85150d15287df049.
Report an issue: GitHub.