Troubleshooting
Common issues and solutions for ZKVAULT development and deployment.
Proof Generation Issues
Error: Constraint not satisfied
Symptom: Proof generation fails with constraint error
Error: Constraint not satisfied at line 42
Signal 'intermediate': Expected 12345, got 54321Causes:
- Incorrect input values
- Circuit logic bug
- Arithmetic overflow in circuit
Solutions:
// 1. Debug with trace logging
zkvault debug \
--circuit circuit.circom \
--witness witness.json \
--trace-level verbose
// 2. Validate inputs before proving
function validateInputs(inputs) {
if (inputs.a < 0 || inputs.a >= FIELD_MODULUS) {
throw new Error('Input a out of range');
}
// Check all inputs...
}
// 3. Test circuit with known-good inputs
zkvault prove \
--circuit circuit.circom \
--witness test_witness.json \
--verboseError: Out of memory during proving
Symptom: Process killed or OOM error during proof generation
Solutions:
// 1. Increase Node.js memory limit
export NODE_OPTIONS="--max-old-space-size=8192"
// 2. Use streaming witness generation
const witness = await circuit.calculateWitnessStreaming(input);
// 3. Optimize circuit (reduce constraints)
// Before: 500,000 constraints
// After: 250,000 constraints (2x memory reduction)
// 4. Use GPU proving for large circuits
zkvault prove \
--circuit circuit.circom \
--witness witness.json \
--backend gpuError: Proving takes too long
Symptom: Proof generation exceeds acceptable time
Solutions:
// 1. Profile circuit to find bottlenecks
zkvault analyze constraints --circuit circuit.circom
// 2. Use optimized proving backend
zkvault prove --backend gpu // 3-5x faster
// 3. Optimize circuit structure
// Bad: Many small constraints
for (var i = 0; i < 1000; i++) {
component hash[i] = Poseidon(2);
}
// Good: Batched operations
component hashTree = PoseidonTree(1000);
// 4. Cache compiled circuits
zkvault config set proving.cache_circuits true
// 5. Pre-compute witness generation
const witness = await precomputeWitness(input);Verification Issues
Error: Pairing check failed
Symptom: Verification fails with pairing check error
Error: Proof verification failed - pairing check failedCauses:
- Proof generated with wrong verification key
- Public inputs mismatch
- Corrupted proof data
- Wrong proof protocol (Groth16 vs PLONK)
Solutions:
// 1. Verify proof format
zkvault proof validate proof.json
// 2. Check VK matches circuit
zkvault vk check-compatibility \
--circuit circuit.r1cs \
--vk vk.json
// 3. Validate public inputs
const expectedInputs = [123, 456, 789];
const actualInputs = proof.publicInputs;
assert.deepEqual(actualInputs, expectedInputs);
// 4. Re-generate proof with correct VK
zkvault prove \
--circuit circuit.circom \
--witness witness.json \
--vk vk.json // Specify correct VK
// 5. Check proof hasn't been corrupted
const proofHash = computeHash(proof);
console.log('Proof hash:', proofHash);Error: Compute unit limit exceeded
Symptom: On-chain verification fails due to CU limit
Error: Transaction exceeded compute unit limit (400000)Solutions:
// 1. Estimate CU before submission
const estimate = await zkvault.estimateComputeUnits(proof);
console.log(`Estimated CU: ${estimate}`);
// 2. Request additional compute units
const tx = await program.methods
.verifyProof(proof)
.preInstructions([
ComputeBudgetProgram.setComputeUnitLimit({
units: 500_000,
}),
])
.rpc();
// 3. Use proof compression
const compressed = await zkvault.compress(proof, 'high');
// Verification is faster with compressed proofs
// 4. Split verification into multiple transactions
// For very large proofs, use incremental verification
await verifyProofIncremental(proof, {
chunkSize: 100_000, // CU per transaction
});
// 5. Optimize circuit for on-chain verification
// Reduce number of public inputs
// Use pairing-friendly curve operationsIntegration Issues
Error: Wallet not connected
Symptom: Cannot submit transactions
Solutions:
// 1. Check wallet connection
import { useWallet } from '@solana/wallet-adapter-react';
function MyComponent() {
const { connected, connect } = useWallet();
useEffect(() => {
if (!connected) {
connect().catch(console.error);
}
}, [connected]);
}
// 2. Handle connection errors
try {
await wallet.connect();
} catch (error) {
if (error.name === 'WalletNotReadyError') {
alert('Please install a Solana wallet');
}
}
// 3. Use configured RPC connection
const connection = new Connection('https://api.devnet.solana.com');Error: Transaction simulation failed
Symptom: Transaction fails before submission
Solutions:
// 1. Check account states
const vaultAccount = await program.account.vault.fetch(vaultPda);
console.log('Vault state:', vaultAccount);
// 2. Verify account ownership
require(vaultAccount.authority.equals(wallet.publicKey));
// 3. Check for frozen vault
if (vaultAccount.isFrozen) {
throw new Error('Vault is frozen');
}
// 4. Validate PDAs
const [expectedPda, bump] = PublicKey.findProgramAddressSync(
[Buffer.from('vault'), authority.toBuffer()],
programId
);
// 5. Add simulation logging
const { value: simulationResult } = await connection.simulateTransaction(tx);
console.log('Simulation logs:', simulationResult.logs);Error: RPC rate limit exceeded
Symptom: Too many requests error from RPC
Solutions:
// 1. Implement request throttling
import pThrottle from 'p-throttle';
const throttled = pThrottle({
limit: 10, // 10 requests
interval: 1000, // per second
});
// 2. Use connection pooling
const connections = [
new Connection(RPC_URL_1),
new Connection(RPC_URL_2),
new Connection(RPC_URL_3),
];
let currentIndex = 0;
function getConnection() {
const conn = connections[currentIndex];
currentIndex = (currentIndex + 1) % connections.length;
return conn;
}
// 3. Implement exponential backoff
async function sendWithRetry(tx, maxRetries = 5) {
for (let i = 0; i < maxRetries; i++) {
try {
return await connection.sendTransaction(tx);
} catch (error) {
if (error.message.includes('rate limit')) {
const delay = Math.pow(2, i) * 1000;
await sleep(delay);
continue;
}
throw error;
}
}
}
// 4. Use premium RPC providers
// - Helius, QuickNode, Triton for higher limitsCircuit Issues
Error: Witness generation failed
Symptom: Cannot generate witness from inputs
Solutions:
// 1. Validate input JSON format
const inputs = JSON.parse(inputFile);
assert(inputs.a !== undefined, 'Missing input: a');
// 2. Check for arithmetic errors
// Cause: Division by zero in circuit
signal output quotient <== numerator / denominator;
// Fix: Add zero check
assert(denominator != 0);
// 3. Verify input types
// Circuit expects: signal input a
// Input must be: number or string representing field element
{
"a": "123", // ✓ Correct
"a": 123, // ✓ Correct
"a": "abc", // ✗ Wrong
}
// 4. Check for missing signals
zkvault circuit info circuit.circom
// Lists all required input signalsError: Too many constraints
Symptom: Circuit compilation or proving fails due to size
Solutions:
// 1. Analyze constraint usage
zkvault circuit info circuit.circom
// Output: Constraints: 2,450,123 (too many!)
// 2. Optimize using lookup tables
// Before: 50,000 constraints
for (var i = 0; i < 1000; i++) {
component range = Num2Bits(252);
range.in <== values[i];
}
// After: 5,000 constraints
component lookupTable = RangeLookup(1000);
lookupTable.values <== values;
// 3. Use recursive proofs to split work
// Generate proofs for sub-circuits, then aggregate
// 4. Switch to PLONK (more efficient for some circuits)
zkvault setup --protocol plonk
// 5. Simplify circuit logic
// Remove unnecessary computations
// Combine similar operationsDeployment Issues
Error: Program deployment failed
Symptom: Cannot deploy Solana program
Solutions:
// 1. Check SOL balance
solana balance
// Need ~2 SOL for program deployment
// 2. Verify program size
ls -lh target/deploy/program.so
// Must be < 400KB for standard deployment
// 3. Use verifiable build
anchor build --verifiable
// 4. Deploy with sufficient compute
solana program deploy target/deploy/program.so \
--max-len 400000 \
--with-compute-unit-price 1
// 5. For large programs, use write buffer
solana program write-buffer target/deploy/program.so
solana program deploy <BUFFER_ADDRESS>Error: Verification key upload failed
Symptom: Cannot upload VK to vault
Solutions:
// 1. Check VK file size
ls -lh verification_key.json
// If > 10KB, may need multiple transactions
// 2. Validate VK format
zkvault vk validate verification_key.json
// 3. Chunk large VKs
zkvault vk upload \
--vault $VAULT \
--vk verification_key.json \
--chunked // Automatically splits
// 4. Verify authority
// Only vault authority can upload VK
solana address
// Must match vault.authority
// 5. Check vault state
zkvault vault info $VAULT
// Ensure vault is active, not frozenPerformance Issues
Slow proof generation
Diagnosis:
// Profile proving performance
zkvault benchmark prove \
--circuit circuit.circom \
--witness witness.json \
--iterations 10
// Output:
// Breakdown:
// Witness generation: 8.2s (40%)
// FFT operations: 7.1s (35%)
// Scalar multiplication: 5.1s (25%)Optimizations:
// 1. Use GPU proving
zkvault config set proving.backend gpu
// 3-5x speedup
// 2. Cache witness generation
const witnessCache = new Map();
function getCachedWitness(input) {
const key = hashInput(input);
if (witnessCache.has(key)) {
return witnessCache.get(key);
}
const witness = circuit.calculateWitness(input);
witnessCache.set(key, witness);
return witness;
}
// 3. Parallelize batch proving
await Promise.all(
inputs.map(input => zkvault.prove(circuit, input))
);
// 4. Use WASM for browser proving
// Faster than pure JS implementation
zkvault config set proving.backend wasmDebugging Tools
Enable Debug Logging
// Set log level in code
zkvault.setLogLevel('debug');
// View detailed logs
zkvault prove \
--circuit circuit.circom \
--witness witness.json \
--verbose
// Logs show:
// [DEBUG] Loading circuit...
// [DEBUG] Generating witness...
// [DEBUG] FFT transform...
// [DEBUG] Multiexponentiation...
// [INFO] Proof generated in 12.3sCircuit Debugger
// Interactive circuit debugging
zkvault debug-interactive \
--circuit circuit.circom \
--witness witness.json
// Commands:
// > step - Execute next constraint
// > break 42 - Set breakpoint at line 42
// > print signal - Show signal value
// > trace - Show execution trace
// > continue - Run to next breakpointGetting Help
Support Channels
- GitHub Issues: github.com/zkvault/issues
- Discord: discord.gg/zkvault
- Forum: forum.zkvault.dev
- Email: support@zkvault.dev
Bug Report Template
**Describe the bug**
Clear and concise description.
**To Reproduce**
Steps to reproduce:
1. Load circuit 'example.circom'
2. Generate witness with input {...}
3. Run `zkvault prove ...`
4. See error
**Expected behavior**
What you expected to happen.
**System Information**
- OS: [e.g. Ubuntu 22.04]
- Node version: [e.g. v18.16.0]
- ZKVAULT version: [e.g. 1.2.3]
- Circuit size: [e.g. 50K constraints]
**Logs**
```
Paste relevant logs here
```
**Additional context**
Any other information.