remix-run/remix · error · TypeError
hmr must be a function
Error message
hmr must be a function
What it means
Some `remix test` options require a positive integer. `optionalPositiveInteger` first runs the number check, then rejects values that aren't integers or are below 1 — zero, negatives, decimals, and Infinity all fail `Number.isInteger(n) && n >= 1`.
Source
Thrown at packages/assets/src/lib/asset-server.ts:1084
{
mounts,
rootDir,
},
...getInjectedPackageMountConfigs(),
]),
sourceMapSourcePaths: options.sourceMapSourcePaths ?? 'url',
sourceMaps: options.sourceMaps,
scriptsTarget: resolveScriptTarget(options.target),
stylesTarget: resolveStyleTarget(options.target),
watchOptions,
}
}
function normalizeHmrFactory(factory: AssetServerOptions['hmr']): BrowserHmrChannelFactory | null {
if (factory === undefined) return null
if (typeof factory !== 'function') {
throw new TypeError('hmr must be a function')
}
return factory
}
function createBrowserHmrChannel(
createChannel: BrowserHmrChannelFactory | null,
handleFileEvents: BrowserHmrFileEventHandler,
isClosed: () => boolean,
setUnsubscribe: (unsubscribe: () => void) => void,
): Promise<BrowserHmrChannel | null> {
if (!createChannel) return Promise.resolve(null)
let channelOrPromise: BrowserHmrChannel | undefined | Promise<BrowserHmrChannel | undefined>
try {
channelOrPromise = createChannel()
} catch (error) {
return Promise.reject(error)View on GitHub (pinned to 9696913134)
Solutions
- Use a value of 1 or greater: `--retries 2`
- Default computed zero/empty values to omitting the flag entirely
- Validate in scripts: only pass the flag when the value is a positive integer
Example fix
# before remix test --retries 0 # after remix test --retries 1
Defensive patterns
Strategy: validation
Validate before calling
function positiveIntOrOmit(raw: string | undefined): string[] {
let n = raw === undefined ? NaN : Number(raw);
return Number.isInteger(n) && n >= 1 ? [String(n)] : [];
}
run(['remix','test','--retries', ...positiveIntOrOmit(process.env.RETRIES)]) Type guard
function isPositiveIntegerFlag(v: string): boolean {
let n = Number(v);
return v.trim() !== '' && Number.isInteger(n) && n >= 1;
} Prevention
- Clamp computed counts to >= 1 or omit the flag
- Never pass 0 to retry/worker-style options
When it happens
Trigger: Passing `0`, `-1`, `2.5`, or empty string to a positive-integer option of `remix test` (e.g. retries or worker counts).
Common situations: CI configs computing counts that land on 0; division in scripts producing decimals; empty env vars expanding into the flag.
Understand the failure class
Background: Invalid option value errors: "must be one of", "is not a valid", and "only allows" failures explained — this error's family across 23 libraries.
Related errors
- mounts must include at least one entry
- hmr must create an object
- ${matcherName} requires a mock function with a .mock.calls p
- throw new AssertionError(options)
- throw new AssertionError({ message, actual, expected, operat
AI-assisted analysis of remix-run/remix@9696913134 (2026-08-27).
Data as JSON: /api/errors/bb1c74588db45cbe.
Report an issue: GitHub.