transloadit/uppy · critical · TypeError

[s3mini] endpoint must be a valid URL. Expected format: http

Error message

[s3mini] endpoint must be a valid URL. Expected format: https://<host>[:port][/base-path] But provided: "${raw}"

What it means

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.

Source

Thrown at packages/@uppy/aws-s3/src/s3-client/S3mini.ts:150

    return this.cachedCredentialsPromise
  }

  private _ensureValidUrl(raw: string): string {
    const candidate = /^(https?:)?\/\//i.test(raw) ? raw : `https://${raw}`
    try {
      new URL(candidate)

      // Find the last non-slash character
      let endIndex = candidate.length
      while (endIndex > 0 && candidate[endIndex - 1] === '/') {
        endIndex--
      }
      return endIndex === candidate.length
        ? candidate
        : candidate.substring(0, endIndex)
    } catch {
      const msg = `${C.ERROR_ENDPOINT_FORMAT} But provided: "${raw}"`
      throw new TypeError(msg)
    }
  }

  private _checkKey(key: string): void {
    if (typeof key !== 'string' || key.trim().length === 0) {
      throw new TypeError(C.ERROR_KEY_REQUIRED)
    }
  }

  private _validateUploadPartParams(
    key: string,
    uploadId: string,
    partNumber: number,
  ): void {
    this._checkKey(key)
    if (typeof uploadId !== 'string' || uploadId.trim().length === 0) {
      throw new TypeError(C.ERROR_UPLOAD_ID_REQUIRED)
    }

View on GitHub (pinned to 5d4dedd02a)

Solutions

  1. Fix the endpoint to include protocol and host: `https://s3.us-east-1.amazonaws.com` or `http://localhost:9000` for local MinIO.
  2. If it comes from config/env, trim and validate it at startup before constructing S3mini.
  3. Verify no stray characters, quotes, or newlines in the value (log `JSON.stringify(endpoint)` to see hidden whitespace).
  4. For local development remember http vs https matters; use `http://` only for localhost.

Example fix

// before
const s3 = new S3mini({ endpoint: process.env.S3_ENDPOINT }) // "s3.example.com"
// after
const s3 = new S3mini({ endpoint: 'https://s3.example.com' })
Defensive patterns

Strategy: validation

Validate before calling

function parseEndpoint(raw: string | undefined): URL {
  const trimmed = (raw ?? '').trim()
  if (!/^https?:\/\//.test(trimmed)) throw new Error(`Bad S3 endpoint: ${raw}`)
  return new URL(trimmed)
}
const s3 = new S3mini({ endpoint: parseEndpoint(process.env.S3_ENDPOINT).toString(), ... })

Type guard

const isValidEndpoint = (v: unknown): v is string =>
  typeof v === 'string' && v.trim().length > 0 && /^https?:\/\/[^\s]+$/.test(v.trim())

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of transloadit/uppy@5d4dedd02a (2026-08-28). Data as JSON: /api/errors/fff3440100a5ff17. Report an issue: GitHub.