{"record":{"id":"532499a54e3ac449","repo":"heygen-com/hyperframes","slug":"s3transport-expected-s3-uri-got-json-stri","errorCode":null,"errorMessage":"[s3Transport] expected s3:// URI, got: ${JSON.stringify(uri)}","messagePattern":"\\[s3Transport\\] expected s3:// URI, got: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/aws-lambda/src/s3Transport.ts","lineNumber":48,"sourceCode":"import { pipeline } from \"node:stream/promises\";\nimport {\n  GetObjectCommand,\n  HeadObjectCommand,\n  PutObjectCommand,\n  type S3Client,\n} from \"@aws-sdk/client-s3\";\nimport * as tar from \"tar\";\n\n/** Parsed `s3://bucket/key` URI. */\nexport interface S3Location {\n  bucket: string;\n  key: string;\n}\n\n/** Parse `s3://bucket/key/path` → `{ bucket, key }`. Throws on malformed input. */\nexport function parseS3Uri(uri: string): S3Location {\n  if (!uri.startsWith(\"s3://\")) {\n    throw new Error(`[s3Transport] expected s3:// URI, got: ${JSON.stringify(uri)}`);\n  }\n  const rest = uri.slice(\"s3://\".length);\n  const slash = rest.indexOf(\"/\");\n  if (slash === -1) {\n    throw new Error(`[s3Transport] missing key in s3 URI: ${JSON.stringify(uri)}`);\n  }\n  const bucket = rest.slice(0, slash);\n  const key = rest.slice(slash + 1);\n  if (!bucket || !key) {\n    throw new Error(`[s3Transport] empty bucket or key in s3 URI: ${JSON.stringify(uri)}`);\n  }\n  return { bucket, key };\n}\n\n/** Build `s3://bucket/key` from a location. */\nexport function formatS3Uri(loc: S3Location): string {\n  return `s3://${loc.bucket}/${loc.key}`;\n}","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/heygen-com/hyperframes/blob/c2996c8626135db5253519359d8a063d3bafad8d/packages/aws-lambda/src/s3Transport.ts#L30-L66","documentation":"Thrown by `parseS3Uri` when the input does not start with the `s3://` scheme. The transport layer only speaks `s3://` URIs; anything else (https, file, bare bucket) is rejected at the boundary before it reaches the S3 SDK.","triggerScenarios":"Calling `parseS3Uri` (directly or via download/upload helpers) with a URI like `https://...`, `bucket/key`, or `arn:aws:s3:::...`.","commonSituations":"Passing an HTTPS S3 console URL where an `s3://` URI was expected; copy-pasting a bucket ARN; configuration loaded a path-style URL; missing scheme prefix after an env-var interpolation.","solutions":["Use the `s3://bucket/key` form for all transport calls.","If your config stores ARNs or HTTPS URLs, convert them to `s3://` at the config boundary.","Use `formatS3Uri({bucket, key})` to construct URIs from parts instead of string concatenation.","Add a unit test that config values match `/^s3:\\/\\//`."],"exampleFix":"// before\nparseS3Uri(\"https://my-bucket.s3.amazonaws.com/key\");\n// after\nparseS3Uri(\"s3://my-bucket/key\");","handlingStrategy":"type-guard","validationCode":"function isS3Uri(value: unknown): value is string {\n  return typeof value === \"string\" && value.startsWith(\"s3://\");\n}","typeGuard":"function isS3Uri(value: unknown): value is string {\n  return typeof value === \"string\" && value.startsWith(\"s3://\");\n}","tryCatchPattern":null,"preventionTips":["Construct URIs with `formatS3Uri({bucket, key})` instead of string concatenation.","Validate config-supplied URIs at load time with `isS3Uri`.","Keep ARNs and HTTPS URLs out of transport config; convert at the boundary."],"tags":["s3","transport","uri","validation"],"backgroundTag":null,"analyzedSha":"c2996c8626135db5253519359d8a063d3bafad8d","analyzedAt":"2026-08-12T22:18:56.877Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}