{"record":{"id":"551d957393e61818","repo":"usestrix/strix","slug":"viewer-ui-is-not-built-nbuild-it-with-cd-strix-i","errorCode":null,"errorMessage":"Viewer UI is not built.\\nBuild it with: cd strix/interface/viewer/frontend && npm ci && npm run build","messagePattern":"Viewer UI is not built\\.\\\\nBuild it with: cd strix/interface/viewer/frontend && npm ci && npm run build","errorType":"console","errorClass":"SystemExit","httpStatus":null,"severity":"error","filePath":"strix/interface/viewer/cli.py","lineNumber":63,"sourceCode":"        default=0,\n        help=\"Port to serve on (default: an available ephemeral port).\",\n    )\n    parser.add_argument(\"--host\", default=\"127.0.0.1\", help=argparse.SUPPRESS)\n    parser.add_argument(\n        \"--no-open\",\n        action=\"store_true\",\n        help=\"Do not open the browser automatically.\",\n    )\n    args = parser.parse_args(argv)\n\n    console = Console()\n\n    if not bundle_is_built():\n        console.print(\n            \"[bold red]Viewer UI is not built.[/]\\n\"\n            \"Build it with: [cyan]cd strix/interface/viewer/frontend && npm ci && npm run build[/]\"\n        )\n        raise SystemExit(1)\n\n    run_dir = _resolve_run_dir(args.run, console)\n\n    httpd, url, token = serve(\n        run_dir,\n        host=args.host,\n        port=args.port,\n        open_browser=not args.no_open,\n    )\n    # The tokened URL is what authorizes the browser (steering, report sending,\n    # history). Print it rather than the bare URL so the operator -- and only\n    # the operator -- can open or share an authorized link.\n    open_url = authorized_url(url, token)\n\n    run_name = run_dir.name\n    summary = read_run_summary(run_dir)\n    live = not summary.get(\"finished\", False)\n","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/usestrix/strix/blob/85513391305171ecc6faffe03da4a8bda5e3febb/strix/interface/viewer/cli.py#L45-L81","documentation":"SystemExit(1) with 'Viewer UI is not built' raised by the viewer CLI (strix/interface/viewer/cli.py main()) when bundle_is_built() reports the frontend asset bundle is missing. The viewer serves a pre-built JS/CSS bundle from strix/interface/viewer/frontend; when the package was installed from source without building the frontend, serving is impossible, so the CLI exits with the exact build command to run.","triggerScenarios":"Running the viewer (e.g. `strix viewer` / python -m strix.interface.viewer.cli) from a source checkout or a wheel built without the frontend step. bundle_is_built() finds no dist bundle, prints the message, and raises SystemExit(1) before binding any port.","commonSituations":"Fresh git clone + `uv run strix ...` without building the frontend; CI installing the package with --no-build-isolation that skips the npm step; node/npm absent from the image so the optional frontend build silently skipped; downstream packagers (Debian, conda) shipping a Python-only build; npm ci failing midway in a Docker build and the error being ignored.","solutions":["Run the exact command shown: cd strix/interface/viewer/frontend && npm ci && npm run build (requires Node.js/npm installed)","If Node is missing, install it first (e.g. via nvm or system package manager), then re-run the build","Use an official release wheel/PyPI install, which ships the pre-built bundle, instead of a source checkout","In Dockerfiles, make the frontend build step fatal (set -e) so a broken build fails the image build instead of deferring to runtime"],"exampleFix":"# before (Dockerfile, silent failure)\nRUN cd strix/interface/viewer/frontend && npm ci && npm run build || true\n# after\nRUN cd strix/interface/viewer/frontend && npm ci && npm run build","handlingStrategy":"validation","validationCode":"from strix.interface.viewer.bundle import bundle_is_built  # adjust import to actual module\n\ndef assert_viewer_ready():\n    if not bundle_is_built():\n        raise SystemExit(\n            \"Viewer UI missing. Run: cd strix/interface/viewer/frontend && npm ci && npm run build\"\n        )","typeGuard":null,"tryCatchPattern":"try:\n    main(argv)\nexcept SystemExit as e:\n    if e.code == 1 and not bundle_is_built():\n        subprocess.run([\"npm\", \"ci\"], cwd=\"strix/interface/viewer/frontend\", check=True)\n        subprocess.run([\"npm\", \"run\", \"build\"], cwd=\"strix/interface/viewer/frontend\", check=True)\n        main(argv)\n    else:\n        raise","preventionTips":["Build the frontend as part of source-setup: make dev-install or the documented npm command","Install from release wheels when Node.js is unavailable","Make npm build steps fatal (set -e / check=True) in Dockerfiles and CI"],"tags":["strix","viewer","build","frontend","cli"],"backgroundTag":null,"analyzedSha":"85513391305171ecc6faffe03da4a8bda5e3febb","analyzedAt":"2026-08-15T05:03:57.275Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}