{"record":{"id":"8f8c690492558a0f","repo":"pocketbase/pocketbase","slug":"failed-to-upload-all-files-w","errorCode":null,"errorMessage":"failed to upload all files: %w","messagePattern":"failed to upload all files: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/field_file.go","lineNumber":548,"sourceCode":"\tvar succeeded []string // list of uploaded file names\n\n\tfor _, upload := range uploads {\n\t\tpath := record.BaseFilesPath() + \"/\" + upload.Name\n\t\tif err := fsys.UploadFile(upload, path); err == nil {\n\t\t\tsucceeded = append(succeeded, upload.Name)\n\t\t} else {\n\t\t\tfailed = append(failed, fmt.Errorf(\"%q: %w\", upload.Name, err))\n\t\t\tbreak // for now stop on the first error since we currently don't allow partial uploads\n\t\t}\n\t}\n\n\tif len(failed) > 0 {\n\t\t// cleanup - try to delete the successfully uploaded files (if any)\n\t\t_, cleanupErr := f.deleteFilesByNamesList(newContextIfInvalid(ctx), app, record, succeeded)\n\n\t\tfailed = append(failed, cleanupErr)\n\n\t\treturn fmt.Errorf(\"failed to upload all files: %w\", errors.Join(failed...))\n\t}\n\n\treturn nil\n}\n\nfunc (f *FileField) deleteNewlyUploadedFiles(ctx context.Context, app App, record *Record) ([]string, error) {\n\tuploaded, _ := record.GetRaw(uploadedFilesPrefix + f.Name).([]*filesystem.File)\n\tif len(uploaded) == 0 {\n\t\treturn nil, nil\n\t}\n\n\tnames := make([]string, len(uploaded))\n\tfor i, file := range uploaded {\n\t\tnames[i] = file.Name\n\t}\n\n\tfailed, err := f.deleteFilesByNamesList(ctx, app, record, list.ToUniqueStringSlice(names))\n\tif err != nil {","sourceCodeStart":530,"sourceCodeEnd":566,"githubUrl":"https://github.com/pocketbase/pocketbase/blob/5d217ddb50cb144d80a5d0b0bdf11b52b2c3e457/core/field_file.go#L530-L566","documentation":"Aggregate error returned when a file upload fails: joins the per-file upload error (126), plus any cleanup error from deleting already-uploaded files. It means the whole upload was aborted and best-effort rollback of partially written files was attempted; if cleanup also failed, that error is in the join too, and orphaned files may remain in storage.","triggerScenarios":"Any record create/update with file uploads where at least one UploadFile fails. The pattern is: upload files in order, stop at first error, delete the succeeded ones, then return errors.Join(uploadErr, cleanupErr).","commonSituations":"Same as 126 (permissions, disk full, S3 issues), plus orphaned-file residue when the cleanup delete also fails — e.g. disk full prevented both the upload and the cleanup, or the context was cancelled (code swaps in a fresh Background context for cleanup to mitigate this).","solutions":["Unwrap with errors.Unwrap/errors.Is on the joined error to separate upload failure from cleanup failure.","Fix the primary upload cause first (see 126).","If cleanupErr is non-nil, scan the record's storage folder (pb_data/storage/<collectionId>/<recordId>/) for orphans and delete them manually.","Retry the request after fixing storage; nothing was persisted for this upload."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"err := app.Save(record)\nif err != nil {\n    var joined interface{ Unwrap() []error }\n    if errors.As(err, &joined) {\n        for _, e := range joined {\n            // separate upload failure from cleanup failure and act accordingly\n        }\n    }\n}","preventionTips":["Because partial uploads are cleaned up, the request is safe to retry as a whole.","Monitor storage health (disk space, S3 reachability) to avoid repeat failures.","If cleanup also failed, sweep the record's storage dir for orphans."],"tags":["files","upload","storage","cleanup"],"backgroundTag":null,"analyzedSha":"5d217ddb50cb144d80a5d0b0bdf11b52b2c3e457","analyzedAt":"2026-08-15T10:06:33.165Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}