Skip to main content

Error Handling

This page covers how to handle Walrus errors programmatically in your applications. For a reference of specific error messages and their solutions, see Troubleshooting Common Errors.

Error categories

Not all errors are equal. Some are safe to retry, some require you to check on-chain state (an operation might have succeeded on-chain even though the client did not receive a confirmation), and some require you to fix your input before trying again. The following table summarizes the most common failure types:

Failure typeRetryableCheck on-chain stateRecommended action
Network timeoutYesYesRetry with exponential backoff
Publisher or aggregator downYesNoTry a different endpoint or use the CLI
Insufficient fundsNoNoAdd SUI or WAL to your wallet
Blob too large for memoryNoNoSplit the blob into smaller chunks
Transaction timeoutConditionalYes (critical)Verify the transaction succeeded before retrying
Invalid blob IDNoNoFix the blob ID format
Blob not foundNoYesVerify the blob exists and has not expired
caution

For transaction timeouts, always check on-chain state before retrying. A timed-out transaction might have succeeded. Retrying without checking can result in duplicate blob registrations and wasted funds.

Implement retry logic with exponential backoff

Transient errors such as network timeouts and temporary node unavailability are common in distributed systems. Use exponential backoff to avoid overwhelming the network with retries.

async function retryWithBackoff<T>(
operation: () => Promise<T>,
maxRetries: number = 5,
): Promise<T> {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await operation();
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
const isRetryable =
message.includes('timeout') || message.includes('network');

if (isRetryable && attempt <= maxRetries) {
const delay = Math.pow(2, attempt) * 1000;
console.log(`Retry attempt ${attempt}/${maxRetries} after ${delay}ms`);
await new Promise((resolve) => setTimeout(resolve, delay));
} else {
throw error;
}
}
}
throw new Error('Max retries exceeded');
}

Use this wrapper for any Walrus operation that might encounter transient failures:

const result = await retryWithBackoff(() =>
client.walrus.writeBlob({ blob: data, epochs: 5, signer }),
);

Only retry errors that are transient. Errors such as insufficient funds, invalid blob IDs, or blobs that are too large do not benefit from retries.

Verify on-chain state after timeouts

When an upload or transaction times out, the operation might have succeeded on-chain even though the client did not receive a confirmation. Always check before retrying.

Using the CLI:

$ sui client tx-block TRANSACTION_ID

Using the Walrus CLI:

$ walrus blob-status --blob-id BLOB_ID

If the transaction succeeded, proceed normally. If it was not found, the transaction might have been dropped from the mempool and is safe to retry.

Capture storage node errors with the TypeScript SDK

When using the Walrus TypeScript SDK, you can capture individual storage node errors during uploads by passing the onError option. This is useful for debugging partial failures where the overall operation succeeds (because 2/3 of nodes responded) but some nodes returned errors.

import { SuiGrpcClient } from '@mysten/sui/grpc';
import { walrus } from '@mysten/walrus';

const client = new SuiGrpcClient({
network: 'testnet',
baseUrl: 'https://fullnode.testnet.sui.io:443',
}).$extend(
walrus({
storageNodeClientOptions: {
onError: (error) => console.log('Storage node error:', error),
},
}),
);

This does not change the behavior of the operation. Uploads still succeed if enough nodes respond. The onError callback provides visibility into which nodes are failing and why.

Use strict consistency checks for critical data

By default, Walrus reads reconstruct the blob from slivers and verify the blob ID. For data where integrity is critical (for example, financial records or credentials), you can request a stricter consistency check that validates each individual sliver against the Merkle tree.

Using the CLI:

$ walrus read BLOB_ID --strict-consistency-check

Using the HTTP API:

$ curl "http://AGGREGATOR_URL:31415/BLOB_ID?consistency=strict"

Strict consistency checks are slower because they verify more data, but they provide stronger guarantees against sliver-level corruption.

Monitor errors in production

Enable verbose logging to capture detailed error information during uploads:

$ RUST_LOG=walrus=debug walrus store file.txt --epochs 5 2>&1 | tee upload.log

To identify recurring error patterns:

$ grep "Error" upload.log | sort | uniq -c

For production deployments using the TypeScript SDK, log errors from the onError callback and track metrics such as retry counts, timeout rates, and storage node error rates.

Debugging checklist

When you encounter an error, follow these steps in order:

  1. Enable debug logging with RUST_LOG=walrus=debug and reproduce the error.
  2. Check system status with walrus info and walrus health --committee.
  3. Verify your configuration is up to date and points to the correct network.
  4. Confirm your wallet has sufficient SUI and WAL balances.
  5. Verify you are using the latest CLI version with walrus --version.
tip

When you set RUST_LOG=info, the walrus CLI prints the path to the configuration file and Sui wallet it uses at startup. This helps confirm you are using the intended configuration.