{"record":{"id":"3d594b9525078f0e","repo":"RocketChat/Rocket.Chat","slug":"result-status","errorCode":null,"errorMessage":"result.status","messagePattern":"result\\.status","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/client/hooks/useEndpointUploadMutation.ts","lineNumber":23,"sourceCode":"\ntype UseEndpointUploadOptions<TData extends UploadResult> = Omit<UseMutationOptions<TData, Error, FormData>, 'mutationFn'>;\n\nexport const useEndpointUploadMutation = <TPathPattern extends PathPattern, TData extends UploadResult = UploadResult>(\n\tendpoint: TPathPattern,\n\toptions?: UseEndpointUploadOptions<TData>,\n) => {\n\tconst sendData = useUpload(endpoint as PathFor<'POST'>);\n\tconst dispatchToastMessage = useToastMessageDispatch();\n\n\treturn useMutation({\n\t\tmutationFn: async (formData: FormData): Promise<TData> => {\n\t\t\tconst data = sendData(formData);\n\t\t\tconst promise = data instanceof Promise ? data : data.promise;\n\t\t\tconst result = await promise;\n\n\t\t\tif (!result.success) {\n\t\t\t\tif (result.status) {\n\t\t\t\t\tthrow new Error(result.status);\n\t\t\t\t}\n\n\t\t\t\tif (typeof result.error === 'string') {\n\t\t\t\t\tthrow new Error(result.error);\n\t\t\t\t}\n\n\t\t\t\tthrow new Error(t('FileUpload_Error'));\n\t\t\t}\n\t\t\treturn result as TData;\n\t\t},\n\t\tonError: (error) => {\n\t\t\tdispatchToastMessage({ type: 'error', message: error });\n\t\t},\n\t\t...options,\n\t});\n};\n","sourceCodeStart":5,"sourceCodeEnd":40,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/f9d3ec372bb580fa8d036f94cf03925a478ef768/apps/meteor/client/hooks/useEndpointUploadMutation.ts#L5-L40","documentation":"Thrown by the useEndpointUploadMutation hook when a file upload completes but the server returns a failed result (success === false) that carries a non-empty `status` string. The UploadResult contract (packages/ui-contexts/src/ServerContext.ts:14) always includes `status`, so the hook treats a truthy status as the most precise error message available and rethrows it. The thrown Error's message is the raw server status string, surfaced to the user via a toast in onError.","triggerScenarios":"Calling the mutation returned by useEndpointUploadMutation with a FormData whose POST to the upload endpoint (e.g. /api/v1/rooms.upload/:rid, /api/v1/users.setAvatar) is rejected by the server with a JSON body like { success: false, status: 'error' } or a mapped status such as 'error-size-limit-exceeded', 'error-invalid-file', etc. Any truthy status field is thrown verbatim.","commonSituations":"Uploading a file that exceeds the server's FileUpload_MaxFileSize setting; uploading a MIME type disallowed by FileUpload_MediaTypeWhiteList/BlackList; avatar upload when the user lacks 'pin-message'/'edit-other-user-info' permissions; the apps-engine file-upload interceptor rejecting the payload; the upload being interrupted mid-stream so the server reports a partial/generic 'error' status.","solutions":["Inspect the toast text — it equals result.status; match it against known server upload statuses (error-size-limit-exceeded, error-invalid-file, error-invalid-file-type) to find the cause.","Check FileUpload_MaxFileSize and the media-type allow/deny lists in Administration > File Upload; ensure the file is within limits and an allowed MIME type.","Verify the calling user has the permission required by the specific endpoint (e.g. 'edit-other-user-info' for avatars).","Confirm the endpoint path passed to useEndpointUploadMutation is a valid POST upload route and that the FormData field name matches what the route expects.","If the status is generic ('error'), inspect the server logs / network response body for the underlying reason, since the client only echoes the status field."],"exampleFix":"// before: caller ignores the failure cause\nconst upload = useEndpointUploadMutation('/v1/rooms.upload/:rid');\nupload.mutate(formData);\n\n// after: inspect error.message to branch on the server status\ntry {\n  await upload.mutateAsync(formData);\n} catch (e) {\n  if (e.message.includes('error-size-limit-exceeded')) {\n    dispatchToast({ type: 'error', message: t('File_Too_Large') });\n  } else {\n    dispatchToast({ type: 'error', message: e.message });\n  }\n}","handlingStrategy":"try-catch","validationCode":"// Validate file size/type against server settings before uploading\nconst maxBytes = settings.get('FileUpload_MaxFileSize');\nconst allowedTypes = settings.get('FileUpload_MediaTypeWhiteList');\nif (file.size > maxBytes) { throw new Error('error-size-limit-exceeded'); }\nif (allowedTypes && !allowedTypes.test(file.type)) { throw new Error('error-invalid-file-type'); }","typeGuard":"function isFailedUploadResult(r: UploadResult): r is UploadResult & { success: false } {\n  return r.success === false;\n}","tryCatchPattern":"try {\n  await upload.mutateAsync(formData);\n} catch (e) {\n  const reason = (e as Error).message; // equals result.status\n  if (reason.includes('error-size-limit-exceeded')) { /* size UX */ }\n  else if (reason.includes('error-invalid-file')) { /* type UX */ }\n  else { dispatchToast({ type: 'error', message: reason }); }\n}","preventionTips":["Validate file size and allowed MIME type client-side before invoking the upload mutation.","Confirm the user has the permission required by the specific upload endpoint.","Use mutateAsync and await it so the thrown status reaches your catch block."],"tags":["file-upload","mutation","server-response","toast"],"backgroundTag":null,"analyzedSha":"f9d3ec372bb580fa8d036f94cf03925a478ef768","analyzedAt":"2026-08-12T19:07:17.372Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}