Skip to content

install.sh fails on fresh clone: uv sync runs before npm run build, hatchling force-include of frontend/dist not satisfied #2

@BCenzoT

Description

@BCenzoT

Summary

install.sh fails on a fresh clone because it invokes uv sync before building the frontend. pyproject.toml declares a force-include of frontend/dist, which is gitignored and therefore absent on a fresh checkout, so hatchling's editable build aborts.

Environment

  • macOS 15 (Darwin 25.2.0)
  • Python 3.12.12 (mise)
  • Node v24.13.0, npm 11.6.2
  • uv 0.9.28
  • Fresh git clone of main (commit 6366ca7)

Reproduction

git clone https://github.com/Detrol/quorum-cli.git
cd quorum-cli
chmod +x install.sh   # required because the executable bit isn't preserved on some clones
./install.sh

Actual behavior

Environment checks pass, then Installing Python dependencies... fails:

× Failed to build `quorum-cli @ file:///.../quorum-cli`
├─▶ The build backend returned an error
╰─▶ Call to `hatchling.build.build_editable` failed (exit status: 1)
    ...
    File ".../hatchling/builders/plugin/interface.py", line 239, in recurse_forced_files
        raise FileNotFoundError(msg)
    FileNotFoundError: Forced include not found:
    /.../quorum-cli/frontend/dist

Expected behavior

./install.sh completes and produces a runnable installation, matching the README's "Manual installation" section.

Root cause

The script orders steps like this:

  • install.sh:86uv sync --quiet (triggers hatchling.build.build_editable for the local project)
  • install.sh:93–99cd frontend && npm install && npm run build (creates frontend/dist/)

But:

  • pyproject.toml:63–65[tool.hatch.build.targets.wheel.force-include] requires frontend/dist to exist at build time:
    [tool.hatch.build.targets.wheel.force-include]
    "frontend/dist" = "quorum/_frontend"
    ".env.example" = "quorum/.env.example"
  • .gitignore:48 excludes frontend/dist/, so a fresh clone never has it.

Hatchling's force-include is a hard requirement; it raises FileNotFoundError if the referenced path is missing. The PyPI install path is unaffected because the wheel is built upstream with frontend/dist already populated.

The README's "Manual installation" section lists the steps in the correct order (frontend build before Python install), so the intended sequence is clear — install.sh simply has them flipped.

What worked on my setup

Reordering install.sh so the frontend build runs before uv sync resolved this on my machine:

- # Install Python dependencies with uv
- echo "Installing Python dependencies..."
- uv sync --quiet
- echo -e "${GREEN}Done${NC}"
-
- echo
-
  # Install and build frontend
  echo "Installing frontend dependencies..."
  cd frontend
  npm install --silent
  echo -e "${GREEN}Done${NC}"

  echo "Building frontend..."
  npm run build --silent
  echo -e "${GREEN}Done${NC}"
  cd ..

  echo
+
+ # Install Python dependencies with uv
+ echo "Installing Python dependencies..."
+ uv sync --quiet
+ echo -e "${GREEN}Done${NC}"
+
+ echo

Workaround (without modifying the script)

cd frontend && npm install && npm run build && cd ..
uv sync
cp .env.example .env

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions