Skip to content

Intermittent PROFILE_NOT_INITIALIZED race during sphere trader spawn on fresh wallets #551

Description

@vrogojin

Summary

sphere trader spawn (sphere-cli trader/spawn.ts) intermittently crashes the host-side process with PROFILE_NOT_INITIALIZED when a brand-new wallet's CommunicationsModule._doSave runs before the OrbitDB adapter has finished connect(). The crash kills sphere-cli before the trader container handshake completes, leaving the tenant orphaned.

ProfileError: [PROFILE:PROFILE_NOT_INITIALIZED] OrbitDB adapter is not connected. Call connect() first.
    at OrbitDbAdapter.ensureConnected (dist/profile/node.js:12632)
    at OrbitDbAdapter.putEntry (dist/profile/node.js:12293)
    at ProfileStorageProvider.writeEnvelope (dist/profile/node.js:22015)
    at ProfileStorageProvider.set (dist/profile/node.js:21952)
    at CommunicationsModule.writeMessagesKey (dist/index.js:42231)
    at async CommunicationsModule._doSave (dist/index.js:42215)
  code: 'PROFILE_NOT_INITIALIZED'

Repro

Hit during manual-test-trader-roundtrip.sh §3 (spawn) after rebuilding the v0.6 trader image against post-#534 sphere-sdk to verify PR #538 end-to-end:

=== Section 3: Spawn alice-trader + bob-trader tenants ===
✓ alice spawn:  alice-trader-25141520  (OK)
✓ sphere wallet use bob
✗ sphere trader spawn …    → PROFILE_NOT_INITIALIZED crash, process dies

Workspace preserved at /tmp/trader-soak-538-rebuild. Snapshots: snapshots/bob-trader-spawn.log contains the full stack.

Host-side environment:

  • sphere-cli: /home/vrogojin/sphere-cli-work/sphere-cli @ fix/issue-48-followups (HEAD c1ff2c1)
  • sphere-sdk: /home/vrogojin/sphere-sdk @ debug/market-log-body (HEAD 8c7d93d — pre-fix(oracle,soak): payments.validate() always reported invalid; stale swap-soak escrow #534 baseline) + 1 dirty line in modules/market/MarketModule.ts
  • Trader image: ghcr.io/vrogojin/agentic-hosting/trader:v0.6 rebuilt against sphere-sdk @ 8b1955a9 (out of process — the host-side error is independent of the trader image content).

Why intermittent — what we already know

The same sphere-cli + same sphere-sdk dist passed these runs earlier today against the same testnet:

Soak Outcome
manual-test-swap-roundtrip.sh State B (#534 only) ALL GREEN
manual-test-swap-roundtrip.sh State C (#534+#536) ALL GREEN
manual-test-trader-roundtrip.sh (first attempt, pre-image-rebuild) Got past §3 spawn cleanly; failed at §8 deal-deadline due to a separate verifyPayout-in-trader-daemon issue (now resolved by the image rebuild)
manual-test-trader-roundtrip.sh (rerun, post-image-rebuild) Failed here at §3 spawn

So the race is intermittent in the host-side wallet-init / OrbitDB-connect flow. Spawn ran ~4 times today against fresh wallets; only the last one hit it.

Open question — what's the trigger?

CommunicationsModule._doSave writing the messages-key envelope shouldn't run before OrbitDbAdapter.connect() is awaited in a clean init path. Two hypotheses to disambiguate:

  1. Save fires during fresh-wallet bring-up before OrbitDB connect resolves. The save targets the messages-key envelope — possibly part of identity-binding-event publishing on first init. If CommunicationsModule.init doesn't await profile connect before queueing the binding-event write, a race opens. Need to read dist/index.js:42215 (_doSave) callers + check whether the write is fire-and-forget or properly gated.
  2. Save fires reactively from a Nostr-relay event arriving mid-init. A spurious inbound DM (from a prior tenant on the same relay, or a transport-binding event) could land while OrbitDbAdapter.connect() is still pending and trigger a save before the adapter is ready. Less likely on a fresh wallet but possible if there's a transport-pubkey collision from bob-25141520 reusing a derivation index.

A check on whether the running soak created a fresh keypair vs reused storage from the alice-25141520 trader's local HM would help — the workspace at /tmp/trader-soak-538-rebuild/peer-bob should show whether .sphere-cli/local-hm/ already had OrbitDB state from a prior boot.

Workaround

Retry the soak — it's intermittent. For automated CI, the spawn should be wrapped in a retry with sphere trader stop cleanup between attempts. Long-term fix: gate CommunicationsModule._doSave (and writeMessagesKey in particular) on await profile.ready() instead of issuing the write before the adapter resolves connect().

Related

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions