Budibase/budibase · error · BadRequestError
File "${fileName}" has no extension, an extension is require
Error message
File "${fileName}" has no extension, an extension is required to upload a file What it means
Thrown by uploadFile when the filename has no extension (the last dot-separated segment is empty). Extensions drive storage keys, content type resolution, and the security extension checks, so extensionless uploads are rejected.
Source
Thrown at packages/server/src/api/controllers/static/index.ts:274
let files = file && Array.isArray(file) ? Array.from(file) : [file]
ctx.body = await Promise.all(
files.map(async file => {
const fileName = getUploadFilename(file)
const filePath = getUploadPath(file)
const rawMimeType = getUploadMimeType(file)
if (!fileName) {
throw new BadRequestError(
"Attempted to upload a file without a filename"
)
}
if (!filePath) {
throw new BadRequestError("Attempted to upload a file without a path")
}
const extension = [...fileName.split(".")].pop()
if (!extension) {
throw new BadRequestError(
`File "${fileName}" has no extension, an extension is required to upload a file`
)
}
const extensionLower = extension.toLowerCase()
const isPublicUser =
ctx.roleId === roles.BUILTIN_ROLE_IDS.PUBLIC ||
ctx.user?.roleId === roles.BUILTIN_ROLE_IDS.PUBLIC
const enforceInvalidExtension = isPublicUser || !env.SELF_HOSTED
if (
enforceInvalidExtension &&
InvalidFileExtensions.includes(extensionLower)
) {
throw new BadRequestError(
`File "${fileName}" has an invalid extension: "${extension}"`
)
}
View on GitHub (pinned to a81a902e9a)
Solutions
- Rename the file to include an extension before upload (e.g. notes.txt)
- Append a filename with extension when creating the FormData entry
- Pick an extension matching the actual content type
Example fix
// before
fd.append('file', blob, 'config')
// after
fd.append('file', blob, 'config.json') Defensive patterns
Strategy: validation
Validate before calling
function hasExtension(name) {
const ext = name.split('.').pop()
return Boolean(ext) && name.includes('.')
} Type guard
const hasFileExtension = (f: { name: string }): f is { name: string } & { ext: string } =>
f.name.includes('.') && f.name.split('.').pop()!.length > 0 Try / catch
try {
await api.uploadFile(fd)
} catch (err) {
if (err instanceof BadRequestError && err.message.includes('has no extension')) {
// rename to include an extension and resend
} else throw err
} Prevention
- Always name uploaded files with a sensible extension
- Handle dotfiles (.gitignore) by renaming before upload
- Derive the extension from the MIME type if the original name lacks one
When it happens
Trigger: Uploading files named like 'README' or '.gitignore' (split('.') yields empty last segment) or blobs given extensionless names.
Common situations: macOS/Linux config or dotfiles, scripts uploading temp files without names, or API clients hardcoding names without extensions.
Related errors
- File "${fileName}" has an invalid extension: "${extension}"
- Stream to upload is invalid/undefined
- Plugin missing .js file.
- File is not valid - cannot upload.
- Plugin must be compressed into a gzipped tarball.
AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29).
Data as JSON: /api/errors/df7f6547b6a32e6c.
Report an issue: GitHub.