transloadit/uppy · error · TypeError

[s3mini] partNumber must be a positive integer

Error message

[s3mini] partNumber must be a positive integer

What it means

A parameter guard inside _validateUploadPartParams, invoked by uploadPart, requiring `partNumber` to be a positive integer (1–10000 in S3 terms). Part numbers index parts within a multipart upload and S3 rejects zero, negatives, fractional values, and non-numbers at the protocol level; s3mini rejects them client-side with a TypeError.

Source

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

  }

  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)
    }
    if (!Number.isInteger(partNumber) || partNumber <= 0) {
      throw new TypeError(
        `${C.ERROR_PREFIX}partNumber must be a positive integer`,
      )
    }
  }

  /**
   * Uploads an object to S3 using XHR for progress tracking.
   */
  public override async putObject({
    key,
    data,
    fileType = C.DEFAULT_STREAM_CONTENT_TYPE,
    onProgress,
    signal,
  }: IT.PutObjectParams) {
    this._checkKey(key)

    const { xhr, url } = await this.request({

View on GitHub (pinned to 5d4dedd02a)

Solutions

  1. Use 1-based part numbers: `parts.map((chunk, i) => ({ partNumber: i + 1, body: chunk }))`.
  2. Coerce strings via Number.parseInt and validate: `const n = Number.parseInt(partNumber, 10); if (!Number.isInteger(n) || n < 1 || n > 10000) throw ...`.

Example fix

// before
chunks.forEach((chunk, i) => s3.uploadPart({ key, uploadId, partNumber: i, body: chunk }))
// after
chunks.forEach((chunk, i) => s3.uploadPart({ key, uploadId, partNumber: i + 1, body: chunk }))
Defensive patterns

Strategy: validation

Validate before calling

const partNumber = Number.parseInt(rawPartNumber, 10)
if (!Number.isInteger(partNumber) || partNumber < 1 || partNumber > 10000) {
  throw new RangeError(`Invalid partNumber: ${rawPartNumber}`)
}

Type guard

const isValidPartNumber = (n: unknown): n is number =>
  Number.isInteger(n) && n >= 1 && n <= 10000

Prevention

When it happens

Trigger: Calling uploadPart with partNumber = 0 (e.g. from a 0-based loop index), a fractional number (1.5), a numeric string ('1'), NaN, or undefined.

Common situations: Using `array.forEach((chunk, i) => uploadPart({ partNumber: i, ... }))` with a 0-based index instead of i+1; parsing part numbers from strings and forgetting Number(); float math producing non-integers.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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