{"record":{"id":"533d9eba7ae47edd","repo":"gitroomhq/postiz-app","slug":"could-not-determine-the-media-size-for-upload-533d9e","errorCode":null,"errorMessage":"Could not determine the media size for upload","messagePattern":"Could not determine the media size for upload","errorType":"exception","errorClass":"BadBody","httpStatus":null,"severity":"error","filePath":"libraries/nestjs-libraries/src/integrations/social/skool.provider.ts","lineNumber":226,"sourceCode":"\n    for (const item of media) {\n      // Size and type come from a HEAD request; the PUT below streams the\n      // bytes so the file is never buffered in memory.\n      const headResponse = await fetch(item.path, {\n        method: 'HEAD',\n        // identity encoding so content-length matches the bytes the GET streams\n        headers: { 'accept-encoding': 'identity' },\n        // @ts-ignore - undici-only option; blocks SSRF to internal IPs\n        dispatcher: getSsrfSafeDispatcher(),\n      });\n      const contentType =\n        headResponse.headers.get('content-type') || 'application/octet-stream';\n      const contentLength = Number(\n        headResponse.headers.get('content-length') || 0\n      );\n      if (!headResponse.ok || !contentLength) {\n        // A permanent condition - fail fast instead of letting Temporal retry\n        throw new BadBody(\n          this.identifier,\n          '{}',\n          '{}',\n          'Could not determine the media size for upload'\n        );\n      }\n      const fileName = item.path.split('/').pop() || 'file';\n\n      const createFileResponse = await (\n        await this.fetch('https://api2.skool.com/files', {\n          method: 'POST',\n          headers: {\n            'Content-Type': 'application/json',\n            Cookie: `auth_token=${cookies.auth_token}; client_id=${cookies.client_id}`,\n          },\n          body: JSON.stringify({\n            file_name: fileName,\n            content_type: contentType,","sourceCodeStart":208,"sourceCodeEnd":244,"githubUrl":"https://github.com/gitroomhq/postiz-app/blob/0f1647f7491a217d43eb5ae7a480484bdf0aff3e/libraries/nestjs-libraries/src/integrations/social/skool.provider.ts#L208-L244","documentation":"SkoolProvider.uploadMediaToSkool does a HEAD request to the media URL to determine size/type before uploading; if the HEAD response is not ok or lacks content-length it throws this BadBody. Marked as a permanent condition so Temporal does not retry uselessly.","triggerScenarios":"HEAD media.url returns non-200 or a missing/zero content-length header — storage signed URL expired, file deleted, or server not returning content-length (chunked).","commonSituations":"Expired S3/cloud URLs, deleted media library entries, misconfigured BACKEND_URL/storage, or a CDN stripping content-length from HEAD responses.","solutions":["curl -I the media URL from the server and confirm 200 + content-length","Fix storage/public-URL configuration (BACKEND_URL, signed URL TTL)","Re-add the media file and retry the post","If the CDN omits content-length, serve media from a source that includes it"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const head = await fetch(url, { method: 'HEAD' });\nif (!head.ok || !Number(head.headers.get('content-length'))) {\n  throw new Error('Media URL lacks size info; fix storage first');\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Ensure storage serves content-length on HEAD","Use long-lived signed URLs for scheduled posts"],"tags":["skool","media-download","content-length"],"backgroundTag":"media-download-failed","analyzedSha":"0f1647f7491a217d43eb5ae7a480484bdf0aff3e","analyzedAt":"2026-08-27T12:09:55.020Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}