Skip to content

Escript build doesn't bundle NIF priv/ — Stats.start_run crashes at boot #46

@corylanou

Description

@corylanou

PR #34 added exqlite (SQLite NIF) as a dependency for token-stats persistence. The orchestrator calls Exqlite.Sqlite3NIF.open/3 in init/1 via Stats.start_run/2.

Problem: mix escript.build bundles BEAM modules but does NOT bundle priv/ directories of dependencies, where NIF shared libraries (.so / .dylib) live. At runtime the escript loads Exqlite.Sqlite3NIF (the BEAM stub) but fails to dlopen the underlying SQLite library, raising :undef on the very first call. Symphony refuses to boot.

Failed to start Symphony ... {:undef, [{Exqlite.Sqlite3NIF, :open, ["/Users/.../.local/share/symphony/stats.db", 6], []}, ...]}

This regression is masked when developing via mix run or iex -S mix because Mix sets up the full project context including NIF priv/ paths. The escript-built binary that operators actually run is broken.

Fix options

  1. Switch from escript to mix release (recommended). Releases bundle dependency priv/ directories and erts. Update make build / docs / install path.
  2. Configure escript_opts to embed exqlite/priv/sqlite3_nif.so (escript doesn't natively support this; would need a custom :embed_extra_applications workaround or a post-build copy step).
  3. Make stats persistence soft-fail when the NIF is unavailable: wrap Stats.start_run/2 in try/rescue, log a warning, set stats_run_id: nil, and degrade gracefully. Token totals would not persist across restarts on broken builds but Symphony would still boot.

Recommend a combination: (1) for the proper packaging path going forward, plus (3) for defense-in-depth so future NIF deps don't repeat this failure mode.

Reproduction

cd elixir && mix deps.get && mix escript.build
./bin/symphony --i-understand-that-this-will-be-running-without-the-usual-guardrails
# Failed to start: :undef on Exqlite.Sqlite3NIF.open

Workaround (operators)

Run via mix instead of the prebuilt escript:

cd elixir && mix run --no-halt -e 'SymphonyElixir.CLI.main(["--i-understand-that-this-will-be-running-without-the-usual-guardrails", "/path/to/WORKFLOW.md"])'

Why now

Surfaced today after PR #34 landed and operators rebuilt the escript to pick up the new feature set. Several other NIF-using libs (e.g. lazy_html) are already in deps; PR #34 was the first to call one at boot.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions