Docs

Troubleshooting

Fix the most common Proa setup, registry, template, component, island, routing, and CI failures.

Open Markdown

Start with the fastest checks. They separate environment problems from template and runtime problems:

proa --help
proa check
proa fmt --check --verify src
proa lint --min-severity info src
proa site check

If you are working from the Proa repository instead of an installed CLI, use the Cargo wrapper:

cargo run -p proa-cli --bin proa -- fmt --check --verify src
cargo run -p proa-cli --bin proa -- lint --min-severity info src

proa: command not found

Right after an install, the cause is PATH. The installer appends an export PATH line to every shell profile it finds (~/.bashrc, ~/.bash_profile, ~/.zshrc, ~/.profile, and ~/.config/fish/config.fish), and the shell you are already in never rereads those files. Open a new terminal, or add the directory to the current shell by hand:

export PATH="$HOME/.proa/bin:$PATH"

Confirm that the binaries landed where you expect:

ls "$HOME/.proa/bin"
"$HOME/.proa/bin/proa" --version

On Windows, the installer writes the directory into your user PATH and into the terminal it ran in, so that terminal can run proa right away. Every other process keeps the PATH it started with, so restart any other terminal or editor before running proa --version there. Check the persisted value with:

[Environment]::GetEnvironmentVariable("Path", "User")

The installer refuses to rewrite a user PATH that contains %VAR% references, because rewriting one would freeze today's expansion. It warns and prints the line to add when it finds one.

If you ran cargo install or the installer fell back to a source build, the binaries live in ~/.cargo/bin instead. Point the same export line at that directory.

If you passed PROA_NO_MODIFY_PATH or --no-modify-path, the installer left your profiles, and the Windows user PATH, alone by design, and printed the line to add. Add it yourself, or run the installer again without that flag.

Every run writes a log that lists which profile files the installer examined, which it changed, and which already had the line. The installer prints the path as it exits, and it looks like /tmp/proa-install-20260813T221500Z-1234.log (under %TEMP% on Windows). Read that when the PATH change did not land where you expected, and attach it if you report the problem.

When you are developing inside this repository, run the CLI through Cargo instead:

cargo run -p proa-cli --bin proa -- --help

Then use that same prefix for later commands. See Install Proa and the CLI reference.

Windows Builds And Executable Launches

Use a current stable Rust toolchain with the MSVC build tools installed, then run proa --version and cargo proa --version. Both entry points should report the installed CLI version. proa dev, proa check, proa build, and proa test coordinate the Cargo passes required for interactive components. Plain cargo check supports Rust type checking and editor feedback; it does not validate the complete linked browser graph. Plain cargo build and cargo run cannot produce a linked application containing RSJS islands.

The release workflow currently publishes a Linux x86_64 CLI archive. Windows installation falls back to building from source, so installation includes a Rust dependency build. The first application build also compiles dependencies for the descriptor and final passes. Later runs reuse those Cargo artifacts. Keep the same toolchain, target, profile, and features when comparing cold and warm build times. In PowerShell, enable stage timing before reproducing a slow build:

$env:PROA_BUILD_TIMINGS = '1'
proa build
Remove-Item Env:PROA_BUILD_TIMINGS

For LNK1104 or errors involving a very long artifact path, use a short Cargo target directory for the same build and dev commands:

$env:CARGO_TARGET_DIR = 'C:\pt'
proa dev

Proa uses shorter directory labels on Windows while retaining complete cache identities. Native linkers and dependency build tools can still impose path limits, so a short target root remains useful for deeply nested checkouts. The shorter layout requires one cold build when upgrading from the old layout; Proa leaves the old artifacts in place. Use a separate target root for unrelated projects if their Cargo builds run concurrently.

For missing tailwindcss.exe, follow the Windows instructions under Tailwind prerequisite.

proa start runs an exported executable. To choose its location explicitly:

proa build --artifact-out target/release/server.exe
proa start --bin target/release/server.exe

If launching or replacing a compiled file fails, preserve the executable path and numeric OS error from the original diagnostic. A successful retry alone does not identify which Windows feature caused the failure:

OS errorMeaning and next check
5Access denied. Check file permissions and the security event for that exact path; this code alone does not identify antivirus.
32, 33Another process holds a file or region lock. Stop an older server still using that output, or wait for the process holding the lock to release it.
577Windows could not verify the file's digital signature. Inspect the Code Integrity events for the named executable or DLL.

These meanings come from Microsoft's system error codes 0–499 and 500–999. Smart App Control can also block untrusted unsigned code. Include the Windows version, active security feature, error code, CLI version, and failing command in a report so the failure can be distinguished from a compiler error or file-lock race.

unsupported_shapes means the linked backend cannot represent a client expression or dependency in the selected component graph. It can appear after Rust compilation because the graph is only complete at link time. The error includes a Rust-resolved component name when one is available.

Run proa lint <component-source.rs> while editing, then proa check for the whole project. Source lint does not prove every cross-component constraint. Use explicitly typed state when inference is ambiguous, a named event handler, and a small reproduction before changing several parts of a mutation at once. For example, save.run(draft.get()) passes the current value; browser handlers cannot implicitly capture arbitrary server-only locals. The exact error and CLI version are needed to distinguish a compiler limitation from an inference or server/browser boundary error.

The Installer Cannot Reach The Download Host

The installer fetches release archives from https://proa.so/downloads/cli, the value of PROA_DOWNLOAD_BASE. A connection failure or a 503 from that host stops the download before there is anything to verify.

A 503 means the release host behind the bridge is unavailable or rate limited. The response carries Retry-After: 30, so wait half a minute and run the installer again. Check the endpoint yourself:

curl --proto '=https' --tlsv1.2 -sS -i https://proa.so/downloads/cli/latest.json

A 200 with a version field means the host is healthy and the problem is between you and it, usually a proxy or a DNS resolver. If the failure persists, build the CLI from source instead:

curl -fsSL https://proa.so/install.sh | PROA_BUILD_FROM_SOURCE=1 sh

Or point the installer at another host that serves the same file names:

curl -fsSL https://proa.so/install.sh | PROA_DOWNLOAD_BASE=https://mirror.example/downloads/cli sh

The installer log records the request and what came back. Its path is printed as the installer exits.

No Release Is Published Yet

https://proa.so/downloads/cli/latest.json answers 404 when no proa-cli release exists. The installer reads that as "there is no version to install" rather than an archive-download failure, and attempts a Cargo build from crates.io instead. That requires a published proa-cli crate. An unversioned source build installs the latest published crate; PROA_VERSION selects an exact published version.

The source build puts proa and cargo-proa in ~/.cargo/bin, not ~/.proa/bin, so look there when the shell cannot find the binary afterwards.

Pinning PROA_VERSION does not change this. A version with no published archives answers 404 on the asset URL too.

Checksum Verification Failed

The installer compares the downloaded archive against the SHA256SUMS file for that release. A mismatch stops the install before the installer unpacks anything, and it deletes the temporary directory it downloaded into, so nothing was installed and no unpacked binary was left behind.

A truncated download, a proxy that rewrote the response, or a stale cache all produce this. Run the installer again first. If the mismatch survives a retry, fetch both files and check them yourself:

VERSION="<published-version>"
TARGET=x86_64-unknown-linux-gnu
BASE="https://proa.so/downloads/cli/$VERSION"
curl --proto '=https' --tlsv1.2 -fLO "$BASE/proa-cli-$VERSION-$TARGET.tar.gz"
curl --proto '=https' --tlsv1.2 -fLO "$BASE/proa-cli-$VERSION-SHA256SUMS"
shasum -a 256 --ignore-missing -c "proa-cli-$VERSION-SHA256SUMS"

Use sha256sum --ignore-missing -c on Linux. A clean download on a different network settles the question: if it verifies there, your first download passed through something that changed it. If it fails there too, do not install the archive. Open an issue with the version, the target triple, and the digest you computed, and attach the installer log. It records the URL it fetched, the expected hash, and the hash it computed. Its path is printed as the installer exits.

To keep moving in the meantime, build the CLI from source instead:

curl -fsSL https://proa.so/install.sh | PROA_BUILD_FROM_SOURCE=1 sh

No Prebuilt Binary For This Platform

For now, Proa publishes one native release binary: x86_64-unknown-linux-gnu, built on Ubuntu 24.04. It supports 64-bit Ubuntu 24.04+ and other glibc 2.39+ Linux systems. On anything else, including older Ubuntu releases, ARM Linux, Alpine and other musl distributions, macOS, Windows, FreeBSD, and 32-bit hosts, the installer reports that it found no matching asset and compiles the CLI with Cargo instead. For an official released version, this fallback builds from crates.io without GitHub credentials:

cargo install proa-cli --locked

Use --version "=<published-version>" to pin a release. Main snapshots require a prebuilt archive. If the snapshot archive is unavailable for your platform, select a published version instead.

That build takes several minutes and needs Rust 1.93.0 or newer plus a C toolchain. On Alpine, install the toolchain first:

apk add build-base

Alpine's packaged Rust lags the 1.93.0 minimum on some releases. Run rustc --version, and install the toolchain with rustup when the packaged one is older. The installer does not install Rust for you: it stops and prints the rustup command instead. And when the only downloader on the system is BusyBox wget, which cannot enforce HTTPS-only transfers, the installer stops and asks for curl before downloading anything:

apk add curl

The source build puts proa and cargo-proa in ~/.cargo/bin, not ~/.proa/bin, so check that directory when the shell cannot find the binary afterwards.

When the fallback surprises you on a platform that does have a published binary, read the installer log. It records the raw uname output, the libc it detected and how, the target triple it resolved, and the asset lookup that came back empty. Attach it if you report the detection as wrong.

Cargo Cannot Download Proa Crates

Generated projects use public crates.io dependencies. Check network access to crates.io, the Cargo error, and your project's proxy configuration. No private proa registry or GitHub token is required.

For an older project using Git dependencies, keep all Proa crates on the same Git URL and revision, and enable net.git-fetch-with-cli when you need your Git credential helper or proxy settings. Migrate dependency declarations together; see Upgrading and CI.

The Page Builds But Styles Are Missing

Generated Tailwind sites write public/styles.css. If the page renders unstyled, rebuild the stylesheet with the same command the proa dev / proa build asset step runs:

tailwindcss -i styles/input.css -o public/styles.css

If tailwindcss is not on PATH, install Tailwind CSS CLI v4 with the Proa installer (curl -fsSL https://proa.so/install.sh | sh -s -- --tailwind-only) or with Homebrew (brew install tailwindcss).

Use --no-tailwind when scaffolding if you want to bring your own stylesheet pipeline.

html_sync! Or html! Does Not Parse

Run the formatter with structural verification first:

proa fmt --check --verify src

Common causes:

SymptomFix
A void element has childrenUse a self-closing element such as <input ... />.
Attribute syntax is split by invalid tokensKeep names like data-state and aria-label as one attribute token.
Dynamic text appears without bracesUse {value} for Rust expressions and quoted text for static strings.
A generated macro body has odd spacingRun proa fmt src, then cargo fmt --all.

See The html! Macro and Format, Lint, And Check.

A Component Has Trait Errors

Most page and component render paths should implement WebRenderSync. Keep the implementation generic over the data loader; the output defaults to the owned RenderBuffer:

use proa::{DataLoader, WebContext, WebRenderSync, WriteError};

impl<L: DataLoader> WebRenderSync<L> for MyComponent {
    fn render(self, cx: &mut WebContext<L>) -> Result<(), WriteError> {
        // ...
        Ok(())
    }
}

If you place a sync component inside an async html! tree, wrap it with proa::to_async(...). If the component awaits data or uses async loaders, implement WebRender and render with html!. See Render traits.

Classes Disappear Or ClassList Fails

ClassList<N> has fixed capacity. Count every segment you add, including optional classes:

let classes = ClassList::<4>::new()
    .add(BASE)
    .add(size.classes())
    .add(variant.classes())
    .add_opt(self.class);

Prefer increasing the capacity over building a String in the render path. See Class composition.

An Island Renders But Clicks Do Nothing

Check the browser network panel first. The page should load the rsjs runtime and the island chunk without 404s.

Then confirm:

See RSJS.

A New Route Returns 404

Run the site checks:

proa site routes
proa site check

Confirm that the route is registered in the router, the page module is exported, and generated metadata points at the same path. See Framework routing and Site commands.

CI Fails But Local Checks Pass

Make CI run the same commands as local development:

cargo fmt --all --check
proa check --locked
proa test --locked

If CI fails before compilation, check access to crates.io and the version requirements in Cargo.toml. Generated sites use public registry dependencies and need no GitHub credential or Cargo registry token. Commit Cargo.lock and use --locked to keep CI on the same resolved dependencies as local development.

For GitHub annotations, run:

proa lint --github --changed --base origin/main

Git selection replaces the path argument: --changed and --base cannot be combined with explicit paths.

See CI / GitHub Actions.

Still Stuck

Capture the exact failing command and a machine-readable diagnostic:

proa lint --json --min-severity info src
proa chunks --json src

Include the failing route, the rendered HTML snippet if a browser page looks wrong, and the first compiler or CLI diagnostic that points at your code.

For an install that failed, attach the installer log instead. The installer prints its path on the way out, on success and on failure, and PROA_LOG=/path/to/file writes it where you choose. Rerun with PROA_VERBOSE=1 to see the same detail in the terminal while you work.

Search

Type at least 2 characters