remix-run/remix · error · TypeError

fingerprint.buildId must be a non-empty string

Error message

fingerprint.buildId must be a non-empty string

What it means

With fingerprinting enabled, `fingerprint.buildId` must be a non-empty string; an empty build id would produce broken asset URLs. This error fires when `buildId` is `''` (or an empty-after-trim string).

Source

Thrown at packages/assets/src/lib/asset-server.ts:1168

      enabled: false
      buildId?: string
    }
  | {
      enabled: true
      buildId: string
    } {
  if (!options.fingerprint) {
    return {
      enabled: false,
    }
  }

  if (typeof options.fingerprint.buildId !== 'string') {
    throw new TypeError('fingerprint.buildId must be a string')
  }

  if (options.fingerprint.buildId.length === 0) {
    throw new TypeError('fingerprint.buildId must be a non-empty string')
  }

  if (options.watch !== false) {
    throw new TypeError('fingerprint cannot be used with watch mode')
  }

  return {
    enabled: true,
    buildId: options.fingerprint.buildId,
  }
}

function normalizeWatchOptions(
  options: AssetServerOptions['watch'],
): AssetServerWatchOptions | null {
  if (options === false) return null
  if (options == null || options === true) return {}
  return options

View on GitHub (pinned to 9696913134)

Solutions

  1. Ensure the build id is actually populated before creating the asset server (await manifest generation first)
  2. Use a guaranteed fallback: `buildId: buildId ?? crypto.randomUUID()`
  3. If fingerprinting is optional, gate it on the presence of a real build id

Example fix

// before
fingerprint: { enabled: true, buildId: process.env.BUILD_ID ?? '' }
// after
let buildId = process.env.BUILD_ID
if (!buildId) throw new Error('BUILD_ID is required when fingerprinting is enabled')
fingerprint: { enabled: true, buildId }
Defensive patterns

Strategy: validation

Validate before calling

if (fingerprint?.enabled && fingerprint.buildId === '') {
  throw new Error('BUILD_ID was empty; refusing to start with fingerprinting')
}

Type guard

function isNonEmptyBuildId(id: unknown): id is string {
  return typeof id === 'string' && id.length > 0
}

Prevention

When it happens

Trigger: Passing `fingerprint: { enabled: true, buildId: '' }`, typically from an unset build variable or a manifest field that hasn't been populated yet.

Common situations: `buildId: process.env.BUILD_ID || ''` patterns; reading a build id from a manifest file before it is generated; CI builds where the id is injected later than config construction.

Related errors


AI-assisted analysis of remix-run/remix@9696913134 (2026-08-27). Data as JSON: /api/errors/931687de7568000d. Report an issue: GitHub.