{"record":{"id":"3b2c541000c49254","repo":"pocketbase/pocketbase","slug":"file-d-q-w","errorCode":null,"errorMessage":"file %d (%q): %w","messagePattern":"file (.+?) \\(%q\\): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"core/field_file.go","lineNumber":606,"sourceCode":"\t\treturn filenames, err\n\t}\n\tdefer fsys.Close()\n\tfsys.SetContext(ctx)\n\n\tvar failures []error\n\n\tfor i := len(filenames) - 1; i >= 0; i-- {\n\t\tfilename := filenames[i]\n\t\tif filename == \"\" || strings.ContainsAny(filename, \"/\\\\\") {\n\t\t\tcontinue // empty or not a plain filename\n\t\t}\n\n\t\tpath := record.BaseFilesPath() + \"/\" + filename\n\n\t\terr := fsys.Delete(path)\n\t\tif err != nil && !errors.Is(err, filesystem.ErrNotFound) {\n\t\t\t// store the delete error\n\t\t\tfailures = append(failures, fmt.Errorf(\"file %d (%q): %w\", i, filename, err))\n\t\t} else {\n\t\t\t// remove the deleted file from the list\n\t\t\tfilenames = append(filenames[:i], filenames[i+1:]...)\n\n\t\t\t// try to delete the related file thumbs (if any)\n\t\t\tthumbsErr := fsys.DeletePrefix(record.BaseFilesPath() + \"/thumbs_\" + filename + \"/\")\n\t\t\tif len(thumbsErr) > 0 {\n\t\t\t\tapp.Logger().Warn(\"Failed to delete file thumbs\", \"error\", errors.Join(thumbsErr...))\n\t\t\t}\n\t\t}\n\t}\n\n\tif len(failures) > 0 {\n\t\treturn filenames, fmt.Errorf(\"failed to delete all files: %w\", errors.Join(failures...))\n\t}\n\n\treturn nil, nil\n}","sourceCodeStart":588,"sourceCodeEnd":624,"githubUrl":"https://github.com/pocketbase/pocketbase/blob/5d217ddb50cb144d80a5d0b0bdf11b52b2c3e457/core/field_file.go#L588-L624","documentation":"Per-file failure entry when FileField deletes a record's files: fsys.Delete(path) failed with something other than filesystem.ErrNotFound. The error records the file's index in the record's filename list, the filename, and the wrapped storage error. These entries are accumulated (not returned immediately) and later joined into error 129.","triggerScenarios":"Deleting a record (or removing files from a file field) where the underlying storage delete fails: permission denied on the local file, S3 delete error, or path issues. Only plain filenames without path separators are attempted; ErrNotFound is tolerated because the file may already be gone.","commonSituations":"pb_data/storage files owned by root after running under a different user; S3 bucket policy forbidding DeleteObject; a file lock on Windows; the record's storage folder having been manually moved or renamed.","solutions":["Check the wrapped error for the storage cause (permission, S3 access denied).","For local storage, fix ownership/permissions on pb_data/storage recursively (chown -R appuser: pb_data).","For S3, add s3:DeleteObject to the bucket policy for the configured credentials.","Manually verify the file at pb_data/storage/<collection>/<record>/ exists if the error seems spurious."],"exampleFix":"// before: running the server as root sometimes, creating root-owned uploads\n// after: always run under the same user and fix existing files\n// chown -R pbuser:pbuser pb_data","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"_, err := field.DeleteFiles(ctx, app, record, names) // or record delete path\nif err != nil {\n    // entries carry index+filename; treat non-fatal for record deletion flows,\n    // log and schedule a storage sweep instead of failing the delete\n}","preventionTips":["Keep consistent ownership/permissions on pb_data/storage.","Grant S3 identities s3:DeleteObject, not just Put/Get.","Never manually move or rename storage subfolders."],"tags":["files","storage","delete","permissions"],"backgroundTag":null,"analyzedSha":"5d217ddb50cb144d80a5d0b0bdf11b52b2c3e457","analyzedAt":"2026-08-15T10:06:33.165Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}