yikart/AiToEarn · error · BadRequestException

Invalid public upload id

Error message

Invalid public upload id

What it means

BadRequestException('Invalid public upload id') is thrown by toPublicUploadUserId when the supplied publicUploadId does not match /^\w-]{8,64}$/ — i.e. it must be 8–64 characters of letters, digits, underscore, or hyphen. The ID is used to synthesize an isolated 'public-<id>' user for anonymous public uploads, so malformed IDs are rejected before touching the assets service.

Source

Thrown at project/aitoearn-backend/libs/assets/src/http/assets-http.controller-base.ts:19

import type { Response } from 'express'
import { BadRequestException, Body, Get, Inject, Param, Post, Query, Res } from '@nestjs/common'
import { GetToken, Public, TokenInfo } from '@yikart/aitoearn-auth'
import { ApiDoc, UserType } from '@yikart/common'
import { AssetStatus } from '@yikart/mongodb'
import * as mime from 'mime-types'
import { AssetsService } from '../assets.service'
import { VideoMetadataService } from '../video-metadata.service'
import { AssetVo } from '../vo/asset.vo'
import { ThumbnailResultVo } from '../vo/thumbnail-result.vo'
import { UploadResultVo } from '../vo/upload-result.vo'
import { CreateUploadSignDto, GetThumbnailQueryDto, OssCallbackDto } from './assets-http.dto'
import { ASSETS_HTTP_OPTIONS, AssetsHttpModuleOptions } from './assets-http.options'

const PUBLIC_UPLOAD_ID_PATTERN = /^[\w-]{8,64}$/

function toPublicUploadUserId(publicUploadId: string) {
  if (!PUBLIC_UPLOAD_ID_PATTERN.test(publicUploadId)) {
    throw new BadRequestException('Invalid public upload id')
  }

  return `public-${publicUploadId}`
}

export abstract class AssetsHttpControllerBase {
  protected readonly userType: UserType

  constructor(
    protected readonly assetsService: AssetsService,
    protected readonly videoMetadataService: VideoMetadataService,
    @Inject(ASSETS_HTTP_OPTIONS) options: AssetsHttpModuleOptions,
  ) {
    this.userType = options.userType ?? UserType.User
  }

  @ApiDoc({
    summary: 'Create Upload Signed URL',

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Generate the public upload ID as an 8–64 char alphanumeric/underscore/hyphen string (e.g. crypto.randomUUID().replace(/-/g,'') or nanoid)
  2. Validate the ID format client-side before calling the endpoint
  3. Strip or re-encode characters that URL encoding may have altered
  4. Use the ID exactly as returned by the public-upload-initiation endpoint instead of constructing one

Example fix

// before
const id = `${userId}:${Date.now()}` // ':' not allowed
// after
const id = crypto.randomUUID().replace(/-/g, '') // 32 chars, matches [\w-]{8,64}
const res = await api.post(`/assets/public/${id}/upload`)
Defensive patterns

Strategy: validation

Validate before calling

const PUBLIC_UPLOAD_ID_RE = /^[\w-]{8,64}$/
if (!PUBLIC_UPLOAD_ID_RE.test(publicUploadId)) throw new Error('public upload id must be 8-64 chars of [A-Za-z0-9_-]')

Type guard

function isValidPublicUploadId(id: unknown): id is string {
  return typeof id === 'string' && /^[\w-]{8,64}$/.test(id)
}

Prevention

When it happens

Trigger: Calling public upload endpoints (via userId getter) with an ID shorter than 8 chars, longer than 64, or containing characters outside [A-Za-z0-9_-] such as ':', '@', spaces, or Mongo ObjectIds with invalid chars (ObjectIds are hex, so usually length is the issue), or an empty/undefined ID.

Common situations: Client generates its own upload session ID with UUIDs containing braces or uses a JWT/email as the ID; ID truncated by URL encoding; version change where old clients send shorter tokens.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31). Data as JSON: /api/errors/af993379cf95a0bb. Report an issue: GitHub.