vxcontrol/pentagi · error
ErrResourcesInvalidRequest
ErrResourcesInvalidRequest
Error message
at least one file is required
What it means
UploadResources requires at least one file in the multipart request. The handler first looks for a `files` (multi-file) field, then falls back to a single `file` field; if neither yields a file header, it returns ErrResourcesInvalidRequest with 'at least one file is required'. There is also an upper bound of resources.MaxUploadFiles.
Source
Thrown at backend/pkg/server/services/resources.go:268
return
}
c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, resources.MaxUploadRequestSize)
multipartForm, err := c.MultipartForm()
if err != nil {
logger.FromContext(c).WithError(err).Error("error reading multipart form for resources upload")
response.Error(c, response.ErrResourcesInvalidRequest, err)
return
}
fileHeaders := multipartForm.File["files"]
if len(fileHeaders) == 0 {
if fh, ferr := c.FormFile("file"); ferr == nil && fh != nil {
fileHeaders = append(fileHeaders, fh)
}
}
if len(fileHeaders) == 0 {
response.Error(c, response.ErrResourcesInvalidRequest, errors.New("at least one file is required"))
return
}
if len(fileHeaders) > resources.MaxUploadFiles {
response.Error(c, response.ErrResourcesInvalidRequest,
fmt.Errorf("too many files: %d exceeds the limit of %d", len(fileHeaders), resources.MaxUploadFiles))
return
}
if err := resources.EnsureResourcesDir(s.dataDir); err != nil {
logger.FromContext(c).WithError(err).Error("failed to ensure resources directory")
response.Error(c, response.ErrInternal, err)
return
}
blobsDir := resources.ResourcesDir(s.dataDir)
var totalSize int64
pendingList := make([]pendingResourceUpload, 0, len(fileHeaders))
seenPaths := make(map[string]struct{}, len(fileHeaders))View on GitHub (pinned to ea665308ba)
Solutions
- Attach at least one file via multipart form field `files` (or a single `file` field) in the POST request
- Verify the request Content-Type is multipart/form-data and the client actually appends the File/Blob objects
- Check file count stays within resources.MaxUploadFiles
Example fix
// before curl -X POST https://localhost:8443/api/v1/resources -H 'Authorization: Bearer ...' # no file sent // after curl -X POST https://localhost:8443/api/v1/resources -H 'Authorization: Bearer ...' -F 'files=@report.pdf'
Defensive patterns
Strategy: validation
Validate before calling
if (!files || files.length === 0) throw new Error('select at least one file before uploading');
if (files.length > MAX_UPLOAD_FILES) throw new Error('too many files'); Type guard
function hasFiles(f: FormData): boolean {
return f.getAll('files').length > 0 || f.get('file') !== null;
} Try / catch
try {
await api.post('/resources', formData, { headers: { 'Content-Type': 'multipart/form-data' } });
} catch (e) {
if (e.response?.data?.code === 'ErrResourcesInvalidRequest' && /file is required/.test(e.response.data.message)) {
// prompt user to pick a file
}
} Prevention
- Always append File objects to FormData under `files` (or `file`)
- Disable the upload button until files.length > 0
- Confirm Content-Type is multipart/form-data and the client is not sending JSON
When it happens
Trigger: POSTing the upload endpoint with an empty multipart body, using the wrong form field name (neither `files` nor `file`), sending files as raw body instead of multipart/form-data, or all entries present but empty.
Common situations: Client library serializes files under a different field name; curl invocation omits -F; frontend form not including the File objects; content-type not multipart so FormFile parses nothing.
Related errors
- FlowFiles.InvalidRequest
- Prompts.InvalidRequest
- file name is required
- invalid UsageStatsPeriod: %s
- Internal
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/42eb7c0e801eaac3.
Report an issue: GitHub.