{"record":{"id":"fff3440100a5ff17","repo":"transloadit/uppy","slug":"s3mini-endpoint-must-be-a-valid-url-expected-fo","errorCode":null,"errorMessage":"[s3mini] endpoint must be a valid URL. Expected format: https://<host>[:port][/base-path] But provided: \"${raw}\"","messagePattern":"\\[s3mini\\] endpoint must be a valid URL\\. Expected format: https://<host>\\[:port\\]\\[/base-path\\] But provided: \"(.+?)\"","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"critical","filePath":"packages/@uppy/aws-s3/src/s3-client/S3mini.ts","lineNumber":150,"sourceCode":"    return this.cachedCredentialsPromise\n  }\n\n  private _ensureValidUrl(raw: string): string {\n    const candidate = /^(https?:)?\\/\\//i.test(raw) ? raw : `https://${raw}`\n    try {\n      new URL(candidate)\n\n      // Find the last non-slash character\n      let endIndex = candidate.length\n      while (endIndex > 0 && candidate[endIndex - 1] === '/') {\n        endIndex--\n      }\n      return endIndex === candidate.length\n        ? candidate\n        : candidate.substring(0, endIndex)\n    } catch {\n      const msg = `${C.ERROR_ENDPOINT_FORMAT} But provided: \"${raw}\"`\n      throw new TypeError(msg)\n    }\n  }\n\n  private _checkKey(key: string): void {\n    if (typeof key !== 'string' || key.trim().length === 0) {\n      throw new TypeError(C.ERROR_KEY_REQUIRED)\n    }\n  }\n\n  private _validateUploadPartParams(\n    key: string,\n    uploadId: string,\n    partNumber: number,\n  ): void {\n    this._checkKey(key)\n    if (typeof uploadId !== 'string' || uploadId.trim().length === 0) {\n      throw new TypeError(C.ERROR_UPLOAD_ID_REQUIRED)\n    }","sourceCodeStart":132,"sourceCodeEnd":168,"githubUrl":"https://github.com/transloadit/uppy/blob/5d4dedd02a1ac0ae022c75c54aca76558f88e256/packages/@uppy/aws-s3/src/s3-client/S3mini.ts#L132-L168","documentation":"s3mini validates the endpoint URL before use and throws a TypeError if it cannot be parsed into the expected `https://<host>[:port][/base-path]` form. This guard runs in the constructor so an malformed URL fails immediately rather than producing broken signatures or cryptic XHR failures later. The offending raw value is included in the message.","triggerScenarios":"Passing an endpoint without a scheme (`s3.example.com`), with a typo (`htp://...`), with whitespace, or a non-string (e.g. an object from env parsing). Any endpoint value that throws inside the URL-normalization logic lands in the catch and rethrows this TypeError.","commonSituations":"Reading the endpoint from an environment variable that is unset/malformed; copying a MinIO/Cloudflare R2/Backblaze B2 endpoint and dropping the `https://` prefix; trailing spaces from config files or YAML multiline strings; API gateway URLs with unusual characters.","solutions":["Fix the endpoint to include protocol and host: `https://s3.us-east-1.amazonaws.com` or `http://localhost:9000` for local MinIO.","If it comes from config/env, trim and validate it at startup before constructing S3mini.","Verify no stray characters, quotes, or newlines in the value (log `JSON.stringify(endpoint)` to see hidden whitespace).","For local development remember http vs https matters; use `http://` only for localhost."],"exampleFix":"// before\nconst s3 = new S3mini({ endpoint: process.env.S3_ENDPOINT }) // \"s3.example.com\"\n// after\nconst s3 = new S3mini({ endpoint: 'https://s3.example.com' })","handlingStrategy":"validation","validationCode":"function parseEndpoint(raw: string | undefined): URL {\n  const trimmed = (raw ?? '').trim()\n  if (!/^https?:\\/\\//.test(trimmed)) throw new Error(`Bad S3 endpoint: ${raw}`)\n  return new URL(trimmed)\n}\nconst s3 = new S3mini({ endpoint: parseEndpoint(process.env.S3_ENDPOINT).toString(), ... })","typeGuard":"const isValidEndpoint = (v: unknown): v is string =>\n  typeof v === 'string' && v.trim().length > 0 && /^https?:\\/\\/[^\\s]+$/.test(v.trim())","tryCatchPattern":null,"preventionTips":["Normalize/trim endpoints from env vars and config files before use.","Fail fast on config parse errors at startup with a descriptive message including the raw value."],"tags":["aws-s3","endpoint","url-validation","configuration"],"backgroundTag":"invalid-url-format","analyzedSha":"5d4dedd02a1ac0ae022c75c54aca76558f88e256","analyzedAt":"2026-08-28T12:18:41.267Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}