{"record":{"id":"94e2237a65f7555d","repo":"jackwener/OpenCLI","slug":"upload-error","errorCode":"UPLOAD_ERROR","errorMessage":"S3 upload failed: ${getErrorMessage(error)}","messagePattern":"S3 upload failed: (.+?)","errorType":"error_code","errorClass":"CliError","httpStatus":null,"severity":"error","filePath":"clis/paperreview/utils.js","lineNumber":140,"sourceCode":"}\nexport function createUploadForm(urlData, pdfFile) {\n    const form = new FormData();\n    for (const [key, value] of Object.entries(urlData.presigned_fields ?? {})) {\n        form.append(key, value);\n    }\n    form.append('file', new Blob([new Uint8Array(pdfFile.buffer)], { type: 'application/pdf' }), pdfFile.fileName);\n    return form;\n}\nexport async function uploadPresignedPdf(presignedUrl, pdfFile, urlData) {\n    let response;\n    try {\n        response = await fetch(presignedUrl, {\n            method: 'POST',\n            body: createUploadForm(urlData, pdfFile),\n        });\n    }\n    catch (error) {\n        throw new CliError('UPLOAD_ERROR', `S3 upload failed: ${getErrorMessage(error)}`, 'Try again in a moment');\n    }\n    if (!response.ok) {\n        const body = await response.text();\n        throw new CliError('UPLOAD_ERROR', body || `S3 upload failed with status ${response.status}.`, 'Try again in a moment');\n    }\n}\nexport function summarizeSubmission(options) {\n    const { pdfFile, email, venue, token, message, s3Key, dryRun = false, status } = options;\n    return {\n        status: status ?? (dryRun ? 'dry-run' : 'submitted'),\n        file: pdfFile.fileName,\n        file_path: pdfFile.resolvedPath,\n        size_bytes: pdfFile.sizeBytes,\n        email,\n        venue,\n        token: token ?? '',\n        review_url: token ? buildReviewUrl(token) : '',\n        message: message ?? '',","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/paperreview/utils.js#L122-L158","documentation":"uploadPresignedPdf() POSTs a multipart form (presigned fields plus the PDF blob) to the presigned S3 URL. If fetch rejects before a response arrives, it throws UPLOAD_ERROR 'S3 upload failed: <cause>'. This wraps network-level upload failures to the S3 presigned endpoint, separate from S3 returning an HTTP error.","triggerScenarios":"fetch(presignedUrl, { method: 'POST', body: form }) rejecting: no network, DNS failure for the S3/bucket hostname, connection reset mid-upload of a large body, request timeout, TLS error, or FormData/Blob construction failure (e.g. malformed urlData.presigned_fields).","commonSituations":"Large PDF over a flaky connection dropping mid-upload; corporate proxy blocking PUT/POST to *.amazonaws.com; expired presigned URL causing server-side close; missing NODE_EXTRA_CA_CERTS behind TLS interception.","solutions":["Retry the upload — the library's own hint is 'Try again in a moment'; presigned flows are typically safe to re-run","Check connectivity to the bucket host: curl -v <presigned-url-domain>","If behind a proxy/firewall, allow HTTPS to s3 / *.amazonaws.com or set HTTPS_PROXY","Regenerate the presigned URL if it may have expired, then retry immediately"],"exampleFix":"// before\nawait uploadPresignedPdf(presignedUrl, pdfFile, urlData); // fails once on flaky network\n// after\nfor (let attempt = 1; attempt <= 3; attempt++) {\n    try { await uploadPresignedPdf(presignedUrl, pdfFile, urlData); break; }\n    catch (e) { if (e.code === 'UPLOAD_ERROR' && attempt < 3) await new Promise(r => setTimeout(r, 1000 * attempt)); else throw e; }\n}","handlingStrategy":"retry","validationCode":"async function canReachS3(presignedUrl) {\n    try { new URL(presignedUrl); }\n    catch { throw new Error('Malformed presigned URL'); }\n    const host = new URL(presignedUrl).hostname;\n    try { await fetch(`https://${host}/`, { method: 'HEAD' }); return true; }\n    catch { return false; }\n}","typeGuard":null,"tryCatchPattern":"for (let attempt = 1; attempt <= 3; attempt++) {\n    try { await uploadPresignedPdf(presignedUrl, pdfFile, urlData); break; }\n    catch (e) {\n        if (e?.code === 'UPLOAD_ERROR' && e.message.startsWith('S3 upload failed:') && attempt < 3) {\n            await new Promise(r => setTimeout(r, 1000 * 2 ** (attempt - 1)));\n        } else throw e;\n    }\n}","preventionTips":["Upload promptly after obtaining the presigned URL (they expire)","Retry network-level uploads with exponential backoff","Allow HTTPS egress to *.amazonaws.com in restricted networks","Keep PDFs compressed to reduce mid-upload connection drops"],"tags":["network","upload","s3","presigned-url"],"backgroundTag":"s3-upload-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}