{"record":{"id":"98f75468392942ef","repo":"windmill-labs/windmill","slug":"invalid-s3-object-json-stringify-s3object-exp","errorCode":null,"errorMessage":"Invalid s3 object ${JSON.stringify(s3Object)}: expected an s3://<storage>/<key> URI (e.g. \"s3:///${s3Object}\" for key \"${s3Object}\" in the default storage) or { s3: <key> }","messagePattern":"Invalid s3 object (.+?): expected an s3://<storage>/<key> URI \\(e\\.g\\. \"s3:///(.+?)\" for key \"(.+?)\" in the default storage\\) or (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"typescript-client/s3Types.ts","lineNumber":62,"sourceCode":"/**\n * Parse an S3 object from URI string or record format\n * @param s3Object - S3 object as URI string (`s3://storage/key`, `s3:///key`\n *   for the default storage) or record. Any other string throws rather than\n *   falling back to an auto-generated key: an auto key is requested by\n *   omitting the object, and a fallback would silently misplace the upload\n *   on any typo.\n * @returns S3 object record with storage and s3 key\n */\nexport function parseS3Object(s3Object: S3Object): S3ObjectRecord {\n  if (typeof s3Object === \"object\") return s3Object;\n  const match = s3Object.match(/^s3:\\/\\/([^/]*)\\/(.+)$/);\n  if (match) return { storage: match[1] || undefined, s3: match[2] };\n  if (s3Object.startsWith(\"s3://\")) {\n    throw new Error(\n      `Invalid s3 object URI ${JSON.stringify(s3Object)}: expected s3://<storage>/<key> with a non-empty key (s3:///<key> for the default storage)`\n    );\n  }\n  throw new Error(\n    `Invalid s3 object ${JSON.stringify(s3Object)}: expected an s3://<storage>/<key> URI (e.g. \"s3:///${s3Object}\" for key \"${s3Object}\" in the default storage) or { s3: <key> }`\n  );\n}\n","sourceCodeStart":44,"sourceCodeEnd":66,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/typescript-client/s3Types.ts#L44-L66","documentation":"parseS3Object normalizes an S3 object reference in typescript-client/s3Objects.ts:62, accepting either an s3://<storage>/<key> URI (s3:///<key> for default storage) or an object like { s3: <key> }. It throws this error when the input is neither a valid URI nor an object with an s3 key, e.g. a bare path or a malformed string.","triggerScenarios":"Calling parseS3Object (directly or via s3Obj or getPresignedS3PublicUrls) with a value that is not an object containing an `s3` field and not a string starting with `s3://` — e.g. passing `\"myfile.json\"` or `\"s3:\"` instead of `\"s3:///myfile.json\"` or `{ s3: \"myfile.json\" }`.","commonSituations":"Passing a bare S3 key where a URI is expected; building the URI by string concat and dropping the `s3://` prefix; reading a path from config/CLI args that was never normalized; extra whitespace or a storage prefix typo like `s3:/storage/key`.","solutions":["Wrap a bare key into the default-storage URI: `s3:///${key}`","Pass an object form instead: `{ s3: key }` with optional `storage`","Check the string starts with `s3://` and has a non-empty key after `<storage>/` before calling","Trim the input; ensure it is a string, not undefined/null"],"exampleFix":"// before\ngetPresignedS3PublicUrls(['reports/q3.json'])\n// after\ngetPresignedS3PublicUrls(['s3:///reports/q3.json'])","handlingStrategy":"validation","validationCode":"function isValidS3Object(o) {\n  if (typeof o === 'string') return o.startsWith('s3://') && /^s3:\\/\\/([^/]*\\/)?.+/.test(o);\n  return o != null && typeof o === 'object' && typeof o.s3 === 'string' && o.s3.length > 0;\n}","typeGuard":"function isS3ObjectInput(v: unknown): v is { s3: string; storage?: string } {\n  return typeof v === 'object' && v !== null && 's3' in v && typeof (v as any).s3 === 'string';\n}","tryCatchPattern":"try {\n  const obj = parseS3Object(input);\n} catch (e) {\n  console.error('Bad S3 reference, expected s3://<storage>/<key> or { s3: key }:', input, e);\n  throw new Error(`Invalid S3 reference: ${input}`);\n}","preventionTips":["Always build URIs with the s3:// prefix, using s3:///<key> for default storage","Prefer the object form { s3: key } to avoid string-format mistakes","Validate inputs at boundaries (CLI args, config files) before calling the client","Trim whitespace from keys read from env/config"],"tags":["s3","validation","input-format"],"backgroundTag":"invalid-s3-uri","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}