{"record":{"id":"da836804a8190648","repo":"remix-run/remix","slug":"hmr-must-create-a-channel-with-a-string-url","errorCode":null,"errorMessage":"hmr must create a channel with a string url","messagePattern":"hmr must create a channel with a string url","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/assets/src/lib/asset-server.ts","lineNumber":1124,"sourceCode":"    if (channel === undefined) return null\n    validateBrowserHmrChannel(channel)\n\n    if (isClosed()) {\n      channel.close()\n      return null\n    }\n\n    setUnsubscribe(channel.onFileEvents(handleFileEvents))\n    return channel\n  })\n}\n\nfunction validateBrowserHmrChannel(channel: unknown): asserts channel is BrowserHmrChannel {\n  if (channel === null || typeof channel !== 'object') {\n    throw new TypeError('hmr must create an object')\n  }\n  if (!('url' in channel) || typeof channel.url !== 'string') {\n    throw new TypeError('hmr must create a channel with a string url')\n  }\n  if (!('close' in channel) || typeof channel.close !== 'function') {\n    throw new TypeError('hmr must create a channel with a close function')\n  }\n  if (!('onFileEvents' in channel) || typeof channel.onFileEvents !== 'function') {\n    throw new TypeError('hmr must create a channel with an onFileEvents function')\n  }\n  if (!('updateWatchedFiles' in channel) || typeof channel.updateWatchedFiles !== 'function') {\n    throw new TypeError('hmr must create a channel with an updateWatchedFiles function')\n  }\n}\n\nfunction normalizeBasePath(basePath: string): string {\n  if (typeof basePath !== 'string') {\n    throw new TypeError('basePath must be a string')\n  }\n\n  return normalizePathname(basePath || '/').replace(/\\/+$/, '') || '/'","sourceCodeStart":1106,"sourceCodeEnd":1142,"githubUrl":"https://github.com/remix-run/remix/blob/9696913134be3a4423513d2775f7b31d6917c049/packages/assets/src/lib/asset-server.ts#L1106-L1142","documentation":"`remix version` prints `context.remixVersion`, which is injected into the CLI context at build/publish time. When it's null/undefined — typically a dev checkout or a broken/incomplete packaging — the command can't print a meaningful version and throws `RMX_REMIX_VERSION_UNAVAILABLE`, with the surrounding catch writing the error to stderr.","triggerScenarios":"Invoking `remix version` when the running CLI's context lacks `remixVersion` (null or undefined), e.g. running from source without the version-injection build step or a corrupted install.","commonSituations":"Running the CLI from a repo checkout; packaging pipelines that skip version injection; corrupted node_modules installs.","solutions":["Use a published CLI from npm: `npx remix version`","If developing the CLI, run the build/version-injection step so `remixVersion` is populated","Reinstall the CLI package in case the install is corrupted"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// Read the version from the installed package instead of the CLI context\nlet version = JSON.parse(fs.readFileSync('node_modules/remix/package.json','utf8')).version;\nconsole.log(version);","typeGuard":"function hasVersion(ctx: { remixVersion: string | null }): boolean {\n  return ctx.remixVersion != null;\n}","tryCatchPattern":"Catch around `remix version`; on failure fall back to reading node_modules/remix/package.json for the version string.","preventionTips":["Use published npm CLIs for version checks","Avoid relying on dev-checkout CLIs in CI","Reinstall the CLI if version reporting breaks"],"tags":["cli","version","packaging"],"backgroundTag":"version-metadata-unavailable","analyzedSha":"9696913134be3a4423513d2775f7b31d6917c049","analyzedAt":"2026-08-27T19:55:01.024Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}