Skip to main content

Troubleshooting

Each entry gives the symptom as it appears, what causes it, and what to do. Entries link to the page that explains the mechanism.

Verifying presentations​

SymptomCauseFix
PROOF_INVALID from verifyZkPresentationProofThe proof does not verify against the circuit artifact the verifier loaded. Usually a zk-artifacts version that does not match the prover's.Pin credential and zk-artifacts to the same release on both sides and verify the artifact digest as the artifact package describes.
PUBLIC_INPUT_MISMATCH (with publicInput naming the field)The expected inputs the verifier built differ from the ones the proof was made for: a different challenge, audience, time, programme or country.Build the expected inputs from the request your backend stored, never from the submitter. See Verify presentations.
ISSUER_ROOT_MISMATCH or REVOCATION_ROOT_INVALID from POST /v1/verify, or your own "root not accepted on chain"The wallet proved against a root the chain no longer accepts: the issuer set or revocation tree changed and the root window has passed, or the wallet's lists were stale.Ask the holder to refresh and prove again. If it repeats, check that the verifier reads the contracts on the intended chain.
STALE_CURRENT_TIMEThe request's currentTime is more than 300 seconds from the wallet's clock.Fix the clock on whichever side is wrong. The limit is deliberate; do not widen it.
CONSUMED_REQUEST, EXPIRED_REQUEST, UNKNOWN_REQUESTThe presentation request was already answered, has expired, or was never created on this server.Create a new request with POST /v1/presentation-requests. In the member app, use New check after expiry and Retry status after a polling error.

Issuing credentials and registering​

SymptomCauseFix
SUBJECT_NOT_ELIGIBLE or SUBJECT_ENROLMENT_PENDINGThe networkId was not registered through this member, or the registration transaction has not landed.Register first with POST /v1/registrations and wait for confirmation. The reference policy approves exactly the identities it registered.
LEVEL_BELOW_MINIMUMThe device key's attested security level is below the issuer's MIN_DEVICE_SECURITY_LEVEL. Dev builds on the software keystore send no attestation chain.For local work set the issuer's minimum to SOFTWARE. For anything else keep TRUSTED_ENVIRONMENT or higher and use a release build on a device with a hardware keystore.
DEVICE_ATTESTATION_REJECTED or DEVICE_ATTESTATION_UNAVAILABLEThe attestation chain failed verification, or the wallet sent none.Rebuild the wallet so it regenerates its keys with an attestation challenge; see the user app README.
STATUS_LIST_UNAVAILABLEThe issuer could not reach Google's attestation status list.Allow outbound access to it from the issuer service.
MEMBER_NOT_APPROVEDThe member's Semaphore commitment is not in the approved-member group, so it cannot produce the proof a registry write needs.Finish admission through governance, and confirm MEMBER_IDENTITY_SECRET matches the commitment that was admitted.
NOT_CONFIGURED or CHAIN_MISSINGA route needs settings the service was started without.Check the issuer service configuration.
Revocations disappear after a restartALLOW_IN_MEMORY_REVOCATION=true keeps them in process memory and never writes the chain.Use it only in local tests. See Keep the safe defaults.
Indexer stops finding a user's accounts after a key changeRows written under the old ENCRYPTION_KEY or LOOKUP_HASH_KEY are never scanned again.Before changing either key, DELETE /keys/:networkId for each user; after, POST /keys again with the original fromBlock. See Protect your secrets.
Service refuses a key or token at startupMEMBER_SERVER_TOKEN is under 16 characters, or a 32-byte key is in the wrong format.The indexer takes 0x plus 64 hex characters; the issuer service takes 64 hex characters with no prefix.

Wallet and member apps​

SymptomCauseFix
The app will not run in Expo GoThe wallet needs two native modules, the keystore and the prover, that Expo Go does not ship.Make a dev build: yarn workspace user-app android.
"This wallet needs Android 12 or newer"Android below API 31 has no key-agreement purpose in the keystore.Use a device or emulator on Android 12 or later.
PROOF_FAILED returned to the member appThe native prover library failed to load on the first proof. It loads lazily so that a load failure does not stop the wallet from starting.Rebuild the wallet from a clean prebuild; check that noir-prover-ffi is installed for the device's ABI.
First launch hangs with SocketTimeoutExceptionMetro advertised the laptop's LAN address, which a phone on USB only cannot route to.Reverse the ports with adb reverse and pin the hostname as the user app README shows.
Installing Member B removed Member ABoth member apps were built from the same prebuild and share an application id.Build each with its own prebuild: prebuild:a --clean then android:a, and prebuild:b --clean then android:b. See the Sepolia demo.
A deep link got no answerIt arrived while the wallet was replacing its keys after a lock-screen change, or the wallet was not running.Retry the request.
A credential record will not open; the wallet throws on readThe encrypted store was written under a different key.Settings, then Erase everything, and re-enrol.
The dev launcher's error screen crashes the appA known crash in expo-dev-launcher 6.0.21 when its buttons are tapped.Relaunch from the launcher without tapping the error screen.

Local and testnet stack​

SymptomCauseFix
The stack refuses the deployment fileThe committed 11155111.json describes another network, owned by a different OWNER and with governance never configured, or the file's chain id or contract code does not match.Deploy your own network as the Sepolia demo shows. The deploy rewrites the file, so the stack finds it without DEPLOYMENT_FILE.
eth_getLogs errors or events never arriveThe RPC provider caps log ranges below STACK_LOG_WINDOW_BLOCKS (10,000 by default). Alchemy's free tier allows 10 blocks.Use a provider that serves the range, or lower STACK_LOG_WINDOW_BLOCKS to what it allows.
Nonce errors during genesisGenesis and the serving stack both sign as OWNER.Stop the stack before yarn stack:genesis. A rerun of genesis only sends what is missing.
The preflight refuses with an ETH figureOWNER or DEPLOYER holds less than the deploy or genesis needs.Fund to the figure it prints. Rough totals are in the Sepolia demo.
Dashboard or proxy answers 421The request's Host was a DNS name; the testnet stack accepts an IPv4 address only.Use the IPv4 address that STACK_HOST names.
Governance events show up half a minute lateMember servers and the dashboard read events two blocks after they land.Wait; --check already does.
A rerun of the deploy script changed the file's blockEvery deploy uses a fixed salt, so a rerun reuses the contracts and rewrites the block the stack reads logs from.Keep the first run's file and never rerun after genesis. For a fresh network, withdraw the stake, then create new secrets as the Sepolia demo shows.