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/123

View on GitHub (pinned to 934a3fafe5)

Solutions

  1. Send the request as multipart/form-data including at least one file part: curl -F 'certificate=@cert.pem' -F 'certificate_key=@key.pem' ...
  2. Make the file input required in the UI and skip submitting the validate call when no file is selected
  3. 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

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


AI-assisted analysis of NginxProxyManager/nginx-proxy-manager@934a3fafe5 (2026-08-27). Data as JSON: /api/errors/efa5abab7a021193. Report an issue: GitHub.