vxcontrol/pentagi · error
FlowFiles.InvalidRequest
FlowFiles.InvalidRequest
Error message
at least one uploaded file is required
What it means
UploadFlowFiles requires multipart form parts named 'file'; it collects all such parts and rejects the request with FlowFiles.InvalidRequest when none were provided. The endpoint is strictly multi-upload, so an empty upload is a client-side request error rather than a server fault.
Source
Thrown at backend/pkg/server/services/flow_files.go:164
}
c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, flowfiles.MaxUploadRequestSize)
multipartForm, err := c.MultipartForm()
if err != nil {
logger.FromContext(c).WithError(err).WithField("flow_id", flowID).Error("error reading multipart form")
response.Error(c, response.ErrFlowFilesInvalidRequest, err)
return
}
fileHeaders := multipartForm.File["files"]
if len(fileHeaders) == 0 {
fileHeader, formErr := c.FormFile("file")
if formErr == nil && fileHeader != nil {
fileHeaders = append(fileHeaders, fileHeader)
}
}
if len(fileHeaders) == 0 {
err = errors.New("at least one uploaded file is required")
logger.FromContext(c).WithError(err).WithField("flow_id", flowID).Error("missing uploaded files")
response.Error(c, response.ErrFlowFilesInvalidRequest, err)
return
}
if len(fileHeaders) > flowfiles.MaxUploadFiles {
err = fmt.Errorf("too many uploaded files: %d exceeds the maximum allowed count of %d",
len(fileHeaders), flowfiles.MaxUploadFiles)
logger.FromContext(c).WithError(err).WithField("flow_id", flowID).Error("too many uploaded files")
response.Error(c, response.ErrFlowFilesInvalidRequest, err)
return
}
uploadDir := s.flowUploadsDir(flowID)
if err := os.MkdirAll(uploadDir, 0755); err != nil {
logger.FromContext(c).WithError(err).WithField("flow_id", flowID).Error("error creating upload directory")
response.Error(c, response.ErrInternal, err)
return
}View on GitHub (pinned to ea665308ba)
Solutions
- Attach at least one multipart part named exactly 'file': curl -F "file=@./report.txt" https://host/api/v1/flows/<id>/files
- Verify the Content-Type is multipart/form-data (let the HTTP client set the boundary)
- Check the frontend appends to FormData with key 'file' (repeat the key for multiple files)
- Confirm no middleware rewrites or drops the request body
Example fix
// before curl -X POST https://host/api/v1/flows/42/files -F "upload=@a.txt" // after curl -X POST https://host/api/v1/flows/42/files -F "file=@a.txt" -F "file=@b.txt"
Defensive patterns
Strategy: validation
Validate before calling
function assertHasFiles(files: FileList | File[] | null): asserts files is NonNullable<typeof files> {
if (!files || files.length === 0) throw new Error('select at least one file');
}
const fd = new FormData();
for (const f of files) fd.append('file', f); // key must be exactly 'file' Type guard
function hasMultipartFiles(fd: FormData): boolean {
return fd.getAll('file').length > 0;
} Try / catch
try {
await api.post(`/flows/${flowId}/files`, fd, { headers: { 'Content-Type': 'multipart/form-data' } });
} catch (e) {
if (e.response?.data?.code === 'FlowFiles.InvalidRequest') {
alert('Please attach at least one file before uploading.');
return;
}
throw e;
} Prevention
- Always append multipart parts under the exact key 'file'
- Disable the upload button until files are selected
- Never send file uploads as JSON bodies
- Respect flowfiles.MaxUploadFiles on the client side
When it happens
Trigger: POST /flows/{flow_id}/files with no 'file' multipart part — e.g. the field is named 'files', 'upload', or 'attachment', or the body was sent as JSON/base64 instead of multipart/form-data.
Common situations: curl -F field-name mismatches; frontend FormData appending under the wrong key; proxies or clients stripping the multipart body; sending an empty FormData object.
Related errors
- Agentlogs.InvalidRequest
- Assistantlogs.InvalidRequest
- Assistants.InvalidRequest
- Containers.InvalidRequest
- ErrResourcesInvalidRequest
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/3cf4039600c19100.
Report an issue: GitHub.