NginxProxyManager/nginx-proxy-manager · error
No files were uploaded
Error message
No files were uploaded
What it means
This 400 comes from POST /api/nginx/certificates/validate, which uses multipart file uploads (express-fileupload style req.files). If the request contains no file parts, req.files is undefined/null and the route rejects it immediately with "No files were uploaded" before calling internalCertificate.validate.
Source
Thrown at backend/routes/nginx/certificates.js:159
* Validate Certs before saving
*
* /api/nginx/certificates/validate
*/
router
.route("/validate")
.options((_, res) => {
res.sendStatus(204);
})
.all(jwtdecode())
/**
* POST /api/nginx/certificates/validate
*
* Validate certificates
*/
.post(async (req, res, next) => {
if (!req.files) {
res.status(400).send({ error: "No files were uploaded" });
return;
}
try {
const result = await internalCertificate.validate({
files: req.files,
});
res.status(200).send(result);
} catch (err) {
debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`);
next(err);
}
});
/**
* Specific certificate
*
* /api/nginx/certificates/123View on GitHub (pinned to 934a3fafe5)
Solutions
- Send the request as multipart/form-data including at least one file part: curl -F 'certificate=@cert.pem' -F 'certificate_key=@key.pem' ...
- Make the file input required in the UI and skip submitting the validate call when no file is selected
- Confirm the upload middleware (express-fileupload) is mounted on the route and no earlier middleware consumed the body
Example fix
// before
curl -X POST https://npm.example.com/api/nginx/certificates/validate \
-H 'Content-Type: application/json' -d '{}'
// after
curl -X POST https://npm.example.com/api/nginx/certificates/validate \
-F 'certificate=@fullchain.pem' \
-F 'certificate_key=@privkey.pem' Defensive patterns
Strategy: validation
Validate before calling
const hasFiles = (req) =>
!!req.files && Object.keys(req.files).length > 0;
if (!hasFiles(req)) {
return res.status(400).send({ error: 'No files were uploaded' });
}
// proceed to internalCertificate.validate({ files: req.files, ... }) Type guard
type FileUploads = Record<string, UploadedFile>; const hasUploadedFiles = (files: FileUploads | null | undefined): files is FileUploads => !!files && Object.keys(files).length > 0;
Try / catch
const res = await fetch('/api/nginx/certificates/validate', { method: 'POST', body: form });
if (res.status === 400) {
const body = await res.json();
if (body.error === 'No files were uploaded') {
// tell the user to attach cert/key files; do not retry
}
} Prevention
- Require the file inputs client-side before enabling submit
- Always construct FormData with the exact field names the route expects
- Smoke-test multipart flows through the real proxy chain (nginx limits included) in CI
When it happens
Trigger: Sending the request without a multipart/form-data body, sending form fields but no files, misnamed file part (files are looked up by field name later), or a client that sent application/json instead of multipart so req.files was never populated.
Common situations: curl invocations missing -F flags, frontend forms where the file input is optional/empty and submits anyway, proxies or body parsers stripping multipart parts, or the file input's field name not matching what the handler expects.
Related errors
- Database config does not exist! Please read the instructions
- No 2FA challenge pending
- Plugin not found
- Unknown DNS provider '${certificate.meta.dns_provider}'
AI-assisted analysis of NginxProxyManager/nginx-proxy-manager@934a3fafe5 (2026-08-27).
Data as JSON: /api/errors/efa5abab7a021193.
Report an issue: GitHub.