{"record":{"id":"4b05c6b97cc2d746","repo":"slymnoyann/hey-1","slug":"add-a-valid-video-thumbnail-before-posting","errorCode":null,"errorMessage":"Add a valid video thumbnail before posting.","messagePattern":"Add a valid video thumbnail before posting\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"src/hooks/usePostMetadata.tsx","lineNumber":43,"sourceCode":"    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;\n  };\n\n  const getMetadata = useCallback(\n    ({ baseMetadata }: UsePostMetadataProps) => {\n      const primaryAttachment = attachments[0];\n      const hasAttachments = Boolean(primaryAttachment);\n      const isImage = primaryAttachment?.type === \"Image\";\n      const isAudio = primaryAttachment?.type === \"Audio\";\n      const isVideo = primaryAttachment?.type === \"Video\";\n\n      if (!hasAttachments) {\n        return baseMetadata.content?.length > 2000\n          ? article(baseMetadata)\n          : textOnly(baseMetadata);\n      }","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/slymnoyann/hey-1/blob/88c8f9d55340d57a37846ff72f55c2c604e3a566/src/hooks/usePostMetadata.tsx#L25-L61","documentation":"Thrown by getVideoDuration in usePostMetadata.tsx when building metadata for a video post: either no thumbnail URL is set, or videoDurationInSeconds can't be parsed into a finite positive number. Videos on Lens require a cover thumbnail and a duration, so metadata generation refuses to continue without both.","triggerScenarios":"Publishing a video without choosing a thumbnail (videoThumbnail.url empty), a duration string like ''/'NaN'/'0s' fed into Number.parseFloat, or the video element's duration being NaN/Infinity because metadata never loaded or the file is a live/unsupported stream.","commonSituations":"User skips the thumbnail step; thumbnail upload to IPFS failed so decentralizedUrl never populated; duration read before onloadedmetadata fired; seekbar-based duration measurement returning 0 for very short clips.","solutions":["Require thumbnail selection before enabling publish for video posts","Read duration only from the loadedmetadata event and guard Number.isFinite(duration) && duration > 0 at capture time, storing 0 as invalid","If thumbnail upload failed, retry it and keep the composer in 'not ready' state until videoThumbnail.url is truthy","Catch this error and surface a specific message pointing to the missing thumbnail vs invalid duration"],"exampleFix":"// before\nconst duration = Number.parseFloat(videoDurationInSeconds);\nif (!videoThumbnail.url || !Number.isFinite(duration) || duration <= 0) {\n  throw new Error(\"Add a valid video thumbnail before posting.\");\n}\n\n// after: split the two failure modes for clearer UX\nif (!videoThumbnail.url) {\n  throw new Error(\"Add a video thumbnail before posting.\");\n}\nconst duration = Number.parseFloat(videoDurationInSeconds);\nif (!Number.isFinite(duration) || duration <= 0) {\n  throw new Error(\"Could not read video duration; re-select the video file.\");\n}","handlingStrategy":"validation","validationCode":"const hasVideoRequirements = Boolean(\n  videoThumbnail.url &&\n    Number.isFinite(Number.parseFloat(videoDurationInSeconds)) &&\n    Number.parseFloat(videoDurationInSeconds) > 0\n);\nif (isVideoPost && !hasVideoRequirements) {\n  // keep publish disabled; highlight the thumbnail picker\n}","typeGuard":"const hasValidVideoMeta = (thumb: { url?: string }, duration: string): boolean =>\n  Boolean(thumb.url) && Number.isFinite(Number.parseFloat(duration)) && Number.parseFloat(duration) > 0;","tryCatchPattern":"try {\n  const duration = getVideoDuration();\n} catch (e) {\n  if (e instanceof Error && e.message.includes(\"video thumbnail\")) {\n    // route the user to the thumbnail selection step\n  }\n}","preventionTips":["Capture duration from the loadedmetadata event and treat NaN/0 as invalid immediately","Require a thumbnail (default to first generated frame) before publish is enabled","Verify thumbnail IPFS upload succeeded before allowing the video post flow to continue"],"tags":["video","thumbnail","duration","metadata-validation"],"backgroundTag":"video-metadata-invalid","analyzedSha":"88c8f9d55340d57a37846ff72f55c2c604e3a566","analyzedAt":"2026-08-28T16:20:43.640Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}