> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nullark.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Handle SDK errors and transaction status

Turn proof, recovery, fee, and uncertain-submission failures into clear next actions.

Most SDK failures are safe stops: the recovery data is malformed, the proving files are untrusted, the note is spent, or the fee changed while proving. Keep the current input, explain the failed check, and let the user correct it.

## Reconcile before retrying

An RPC or wallet timeout can hide whether submission reached the chain. Query the original hash when you have one, then check the exact deposit commitment or withdrawal nullifier before marking the operation complete.

```ts
import type { HexString } from "@nullark/sdk";

export type SubmissionState = "confirmed" | "reverted" | "submission-uncertain";

export async function reconcileSubmission(input: {
  transactionHash?: HexString;
  readReceipt: (transactionHash: HexString) => Promise<{ status: "success" | "reverted" } | null>;
  // Match the exact deposit commitment or withdrawal nullifier for this operation.
  effectObserved: () => Promise<boolean>;
}): Promise<SubmissionState> {
  if (input.transactionHash !== undefined && !/^0x[0-9a-fA-F]{64}$/.test(input.transactionHash)) {
    throw new Error("Transaction hash must be 32 bytes.");
  }

  let receiptStatus: "success" | "reverted" | undefined;
  if (input.transactionHash !== undefined) {
    try {
      receiptStatus = (await input.readReceipt(input.transactionHash))?.status;
    } catch {
      // The effect check below can still settle an unavailable receipt lookup.
    }
  }

  let effectReadSucceeded = false;
  try {
    effectReadSucceeded = true;
    if (await input.effectObserved()) return "confirmed";
  } catch {
    effectReadSucceeded = false;
    // Keep the result uncertain until either lookup becomes available.
  }

  if (receiptStatus === "reverted" && effectReadSucceeded) return "reverted";
  return "submission-uncertain";
}
```

## Submission uncertain

| Result | Next action |
| --- | --- |
| `confirmed` | Record completion and refresh the private balance |
| `reverted` | Show the revert and rebuild only after the user corrects the cause |
| `submission-uncertain` | Keep any original hash and check the intended effect again later |

The starter has no automatic resend path. That keeps a slow RPC response from turning into a duplicate value-moving request.

## Expected progress

Use a small set of states that match what the integration is actually doing:

1. Checking proving files
2. Preparing proof
3. Recovery saved
4. Ready to submit
5. Submission uncertain
6. Confirmed or reverted

For errors emitted by each protocol stage, see [Failure boundaries](/reference/failure-boundaries.md).
