Budibase/budibase · error · HTTPError
Project package contains unsupported links.
Error message
Project package contains unsupported links.
What it means
readDirectoryRecursively rejects any entry where entry.isSymbolicLink() is true, throwing this 400 HTTPError. Symbolic links inside an extracted archive could point anywhere on the host filesystem, so they are treated as unsafe and the import aborts.
Source
Thrown at packages/server/src/sdk/workspace/projects/backups/imports.ts:196
totals = { files: 0, bytes: 0 }
): Promise<string[]> => {
const entries = await fsp.readdir(dirPath, { withFileTypes: true })
const files: string[] = []
for (const entry of entries) {
const fullPath = join(dirPath, entry.name)
const relPath = relative(rootPath, fullPath)
if (!isSafeArchivePath(relPath)) {
throw new HTTPError("Project package contains unsafe paths.", 400)
}
if (relPath.split(/[\\/]/).length > MAX_PATH_SEGMENTS) {
throw new HTTPError(
"Project package contains paths that are too deep.",
400
)
}
if (entry.isSymbolicLink()) {
throw new HTTPError("Project package contains unsupported links.", 400)
}
if (entry.isDirectory()) {
files.push(
...(await readDirectoryRecursively(fullPath, rootPath, totals))
)
} else {
const stats = await fsp.stat(fullPath)
totals.files += 1
totals.bytes += stats.size
if (totals.files > MAX_PACKAGE_FILES) {
throw new HTTPError("Project package contains too many files.", 400)
}
if (totals.bytes > MAX_EXTRACTED_SIZE_BYTES) {
throw new HTTPError("Project package is too large.", 400)
}
files.push(fullPath)
}
}View on GitHub (pinned to a81a902e9a)
Solutions
- Rebuild the package dereferencing symlinks (tar --dereference / cp -L) so all entries are real files
- Remove symlinked entries from the archive
- Create the package with Budibase's export flow instead of manual archiving
- Audit untrusted packages for links before importing
Example fix
// before tar -czf app.tar.gz app/ # preserves symlinks // after tar -czf --dereference app.tar.gz app/ # stores link targets as regular files
Defensive patterns
Strategy: validation
Validate before calling
const entries = await fsp.readdir(dir, { withFileTypes: true })
if (entries.some(e => e.isSymbolicLink())) throw new Error("Package contains symlinks; dereference before importing") Type guard
null
Try / catch
try {
await importProject(packagePath)
} catch (e) {
if (e instanceof HTTPError && e.message.includes("unsupported links")) {
// rebuild archive with --dereference and retry
} else throw e
} Prevention
- Create archives with tar --dereference or cp -L
- Avoid symlinked assets/node_modules in packaged trees
- Prefer the official export flow over manual archiving
When it happens
Trigger: Importing a package whose extracted directory tree contains symlinks — commonly archives created with tar's default symlink preservation, or packages built on systems that use symlinks for shared assets/node_modules.
Common situations: Building packages with `tar -czf` over a tree containing symlinks; Unix build machines linking node_modules or static assets; tampered packages using links to escape the extraction root.
Related errors
- Project package contains unsafe paths.
- Only HTTP(S) URLs are allowed for query import
- Import url must not contain credentials
- Project package contains invalid JSON in '${basename(filePat
- Project package contains paths that are too deep.
AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29).
Data as JSON: /api/errors/e42dfc763a379d7e.
Report an issue: GitHub.