{"record":{"id":"104b4313ca3fe206","repo":"slymnoyann/hey-1","slug":"please-wait-for-attachments-to-finish-uploading","errorCode":null,"errorMessage":"Please wait for attachments to finish uploading.","messagePattern":"Please wait for attachments to finish uploading\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"src/hooks/usePostMetadata.tsx","lineNumber":28,"sourceCode":"import { usePostLicenseStore } from \"@/store/non-persisted/post/usePostLicenseStore\";\nimport { usePostVideoStore } from \"@/store/non-persisted/post/usePostVideoStore\";\nimport { usePostAudioStore } from \"../store/non-persisted/post/usePostAudioStore\";\n\ninterface UsePostMetadataProps {\n  baseMetadata: any;\n}\n\nconst usePostMetadata = () => {\n  const { videoDurationInSeconds, videoThumbnail } = usePostVideoStore();\n  const { audioPost } = usePostAudioStore();\n  const { license } = usePostLicenseStore();\n  const { attachments } = usePostAttachmentStore();\n\n  const assertUploadedAttachment = (\n    attachment: (typeof attachments)[number] | undefined\n  ) => {\n    if (!attachment?.uri || !attachment.mimeType) {\n      throw new Error(\"Please wait for attachments to finish uploading.\");\n    }\n\n    return { ...attachment, uri: attachment.uri };\n  };\n\n  const formatAttachments = () =>\n    attachments.slice(1).map((attachment) => ({\n      item: assertUploadedAttachment(attachment).uri,\n      type: attachment.mimeType\n    }));\n\n  const getVideoDuration = () => {\n    const duration = Number.parseFloat(videoDurationInSeconds);\n    if (!videoThumbnail.url || !Number.isFinite(duration) || duration <= 0) {\n      throw new Error(\"Add a valid video thumbnail before posting.\");\n    }\n\n    return duration;","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/slymnoyann/hey-1/blob/88c8f9d55340d57a37846ff72f55c2c604e3a566/src/hooks/usePostMetadata.tsx#L10-L46","documentation":"Thrown by assertUploadedAttachment in usePostMetadata.tsx when an attachment lacks a uri or mimeType. Attachments only get these fields after uploadToIPFS completes, so the error means the caller tried to build post metadata while one or more attachments were still uploading (or failed to upload).","triggerScenarios":"Calling formatAttachments or reading uploadedPrimaryAttachment while an upload is in flight (uri still empty), when an upload failed and left the attachment in a partial state, or when publishing with zero attachments where the primary attachment is undefined.","commonSituations":"User hits 'Post' before the upload spinner finishes; upload promise rejected silently so uri never got set; race between the attachment store updating and the publish handler reading it; large media on slow connections exceeding user patience.","solutions":["Disable the post button while any attachment has no uri (track uploading state in the store)","Check assertUploadedAttachment-equivalent conditions in onPublish before proceeding and show 'uploading' feedback instead of throwing","Ensure failed uploads mark the attachment as errored and are removed/retried so they can't block forever","Await the upload promise (or an uploads-complete flag) before invoking metadata generation"],"exampleFix":"// before\nconst onPublish = async () => {\n  const metadata = getMetadata({ baseMetadata }); // may throw mid-upload\n};\n\n// after\nconst isUploading = attachments.some((a) => !a.uri || !a.mimeType);\nconst onPublish = async () => {\n  if (isUploading) {\n    toast.error(\"Please wait for attachments to finish uploading.\");\n    return;\n  }\n  const metadata = getMetadata({ baseMetadata });\n};","handlingStrategy":"validation","validationCode":"const isAttachmentReady = (a: { uri?: string; mimeType?: string }) =>\n  Boolean(a.uri && a.mimeType);\nconst allReady = attachments.every(isAttachmentReady);\nif (!allReady) {\n  toast.error(\"Attachments are still uploading\");\n  return;\n}","typeGuard":"type UploadedAttachment = { uri: string; mimeType: string };\nconst isUploadedAttachment = (\n  a: { uri?: string; mimeType?: string } | undefined\n): a is UploadedAttachment => Boolean(a && a.uri && a.mimeType);","tryCatchPattern":"try {\n  const primary = uploadedPrimaryAttachment();\n} catch (e) {\n  if (e instanceof Error && e.message.includes(\"wait for attachments\")) {\n    // wait or block publish; do not retry immediately\n  }\n}","preventionTips":["Disable the publish action while any attachment lacks uri/mimeType","Mark failed uploads as errored and force remove/retry so they never block publish","Await upload completion promises before enabling metadata generation"],"tags":["attachments","upload","ipfs","race-condition"],"backgroundTag":"upload-not-finished","analyzedSha":"88c8f9d55340d57a37846ff72f55c2c604e3a566","analyzedAt":"2026-08-28T16:20:43.640Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}