{"record":{"id":"b031291810a72683","repo":"heygen-com/hyperframes","slug":"s3transport-upload-source-missing-localpath","errorCode":null,"errorMessage":"[s3Transport] upload source missing: ${localPath}","messagePattern":"\\[s3Transport\\] upload source missing: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/aws-lambda/src/s3Transport.ts","lineNumber":118,"sourceCode":"    throw error;\n  }\n}\n\n/**\n * Upload a local file's contents to an S3 URI using a streaming\n * `PutObjectCommand`. PutObject's 5 GB cap comfortably exceeds the\n * distributed pipeline's 2 GB planDir limit and the typical\n * chunk size (≤ 200 MB), so a single PUT works for every artifact this\n * adapter handles.\n */\nexport async function uploadFileToS3(\n  client: S3Client,\n  localPath: string,\n  uri: string,\n  contentType?: string,\n): Promise<void> {\n  if (!existsSync(localPath)) {\n    throw new Error(`[s3Transport] upload source missing: ${localPath}`);\n  }\n  const { bucket, key } = parseS3Uri(uri);\n  const size = statSync(localPath).size;\n  await client.send(\n    new PutObjectCommand({\n      Bucket: bucket,\n      Key: key,\n      Body: createReadStream(localPath),\n      ContentType: contentType,\n      ContentLength: size,\n    }),\n  );\n}\n\n/**\n * Upload one content-addressed plan-v2 artifact exactly once.\n *\n * Existing objects are reused only when their immutable digest metadata and","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/heygen-com/hyperframes/blob/c2996c8626135db5253519359d8a063d3bafad8d/packages/aws-lambda/src/s3Transport.ts#L100-L136","documentation":"Thrown by `uploadFileToS3` when the local file at `localPath` does not exist (`!existsSync`). The transport refuses to issue a `PutObjectCommand` for a missing source because the SDK would otherwise fail later with a less actionable error and a half-initialized upload.","triggerScenarios":"Calling `uploadFileToS3(client, localPath, uri)` where `localPath` does not point to an existing file on disk.","commonSituations":"Render output written to a different path than the upload call; a prior step failed to produce the file but did not throw; relative path resolved against the wrong working directory; file was cleaned up by a concurrent process before upload.","solutions":["Verify the file exists at `localPath` (absolute path preferred) before calling `uploadFileToS3`.","Ensure the producing step succeeded and wrote to the exact same path.","Use `resolve()`/absolute paths to avoid working-directory ambiguity in Lambda.","Delay cleanup of render output until after the upload completes."],"exampleFix":"// before: relative path, wrong cwd\nawait uploadFileToS3(s3, \"out/render.mp4\", uri);\n// after: absolute, verified\nconst abs = join(workDir, \"out/render.mp4\");\nif (!existsSync(abs)) throw new Error(`render output missing: ${abs}`);\nawait uploadFileToS3(s3, abs, uri);","handlingStrategy":"validation","validationCode":"import { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nfunction assertUploadSourceExists(localPath: string): string {\n  const abs = resolve(localPath);\n  if (!existsSync(abs)) {\n    throw new Error(`upload source missing: ${abs}`);\n  }\n  return abs;\n}\n// call before uploadFileToS3","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pass absolute paths to uploadFileToS3.","Verify the producing step wrote the file (and succeeded) before scheduling the upload.","Defer cleanup of render output until uploads complete.","Add a pre-upload existence check to surface bad paths early."],"tags":["s3","transport","upload","filesystem","validation"],"backgroundTag":null,"analyzedSha":"c2996c8626135db5253519359d8a063d3bafad8d","analyzedAt":"2026-08-12T22:18:56.877Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}