remix-run/remix · error · TypeError
fingerprint cannot be used with watch mode
Error message
fingerprint cannot be used with watch mode
What it means
Fingerprinted asset URLs are content-stable per build and only make sense for immutable, built output. Watch mode rebuilds continuously and serves in-memory assets, so the asset server rejects combining `fingerprint` with `watch !== false`.
Source
Thrown at packages/assets/src/lib/asset-server.ts:1172
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
}
function hasPackages(packages: readonly string[] | undefined): boolean {
return packages !== undefined && packages.length > 0View on GitHub (pinned to 9696913134)
Solutions
- Set `watch: false` when fingerprinting is enabled (production config)
- Split dev/prod configs so dev uses `watch: true` without `fingerprint` and prod uses `fingerprint` with `watch: false`
Example fix
// before
const options = { watch: true, fingerprint: { enabled: true, buildId } }
// after
const options = isDev
? { watch: true }
: { watch: false, fingerprint: { enabled: true, buildId } } Defensive patterns
Strategy: validation
Validate before calling
if (fingerprint?.enabled && watch !== false) {
throw new Error('fingerprint requires watch: false (production config)')
} Prevention
- Keep separate dev and prod option builders so watch/fingerprint never mix
- Gate fingerprinting behind a production flag in one place
When it happens
Trigger: Passing both `fingerprint: { enabled: true, buildId }` and `watch: true` (or omitting `watch`, since the check requires `watch === false`) in the same asset server options.
Common situations: Sharing one config object between dev (`watch: true`) and prod builds and enabling fingerprinting unconditionally; env-driven configs where fingerprinting is on but watch mode was never disabled.
Related errors
- fingerprint.buildId must be a string
- fingerprint.buildId must be a non-empty string
- throw new AssertionError({ message, actual, expected, operat
- expect(received).toThrow() requires a function (got ${typeof
- expected promise to resolve, but it rejected with: ${stringi
AI-assisted analysis of remix-run/remix@9696913134 (2026-08-27).
Data as JSON: /api/errors/d559817d8f620f22.
Report an issue: GitHub.