Troubleshooting
This page documents common issues encountered when building on or operating Specter, along with their causes and solutions.
Chain ID 47474 Instead of 5446
Symptoms:
- Wallet balance shows
0despite receiving tokens from the faucet or transfers. - Transactions fail or are rejected by the RPC.
- MetaMask shows the wrong network name.
Cause: An earlier Avalanche L1 deployment of Specter used Chain ID 47474. That chain is deprecated. The current Specter Testnet uses Chain ID 5446 (0x1546).
Solution:
- Open MetaMask and remove the old network entry with Chain ID
47474. - Add a new network with the correct parameters:
- RPC URL:
https://testnet.specterchain.com - Chain ID:
5446 - Symbol:
GHOST - Decimals:
18
- RPC URL:
- If building a dApp, update your chain configuration (hardcoded chain IDs, wagmi config, etc.) to use
5446.
Using testnet-rpc.umbraline.com
Symptoms:
- RPC requests intermittently fail or time out.
- Block numbers are behind the current chain head.
- Transaction submissions succeed but never confirm.
Cause: The testnet-rpc.umbraline.com endpoint may point to a stale or unmaintained node that is no longer syncing with the current chain.
Solution:
- Switch to the primary RPC endpoint:
https://testnet.specterchain.com. - The
https://testnet.umbraline.comendpoint (without the-rpcprefix) is also valid and maintained. - Update all configuration files, scripts, and environment variables to use the correct endpoint.
Go 1.24.0 Build Error (Sonic / bytedance linkname)
Symptoms:
When building the Specter node binary with Go 1.24.0, the build fails with errors related to go:linkname directives in the bytedance/sonic package:
github.com/bytedance/sonic/internal/rt: //go:linkname must refer to declared function or variable
Cause: Go 1.24.0 introduced stricter enforcement of the //go:linkname compiler directive. The bytedance/sonic JSON library (a transitive dependency via the Cosmos SDK dependency tree) uses //go:linkname to access internal Go runtime symbols, which the stricter compiler rejects.
Solution:
- Upgrade to Go 1.24.1 or later, which relaxes the
linknamerestrictions for existing code. - Alternatively, you can set
GOFLAGS=-ldflags=-checklinkname=0as a temporary workaround, but upgrading Go is the recommended fix.
# Check your Go version
go version
# If go1.24.0, upgrade
# macOS with Homebrew:
brew upgrade go
# Or download directly:
# https://go.dev/dl/
# Verify
go version
# go version go1.24.1 darwin/arm64
# Clean and rebuild
cd specter-chain
go clean -cache
make build
eth_getLogs Returns Empty Results
Symptoms:
- Calls to
eth_getLogsreturn an empty array even though events were emitted. - Event-based indexing (e.g., watching for
CommitmentInsertedevents) misses events. - The webapp's Revels screen shows no history.
Cause: This is a known limitation of the Cosmos EVM implementation. The EVM module's log indexing is not fully compatible with Ethereum's eth_getLogs behavior, particularly for historical queries and large block ranges.
Solution:
- Use the Specter relayer indexer instead of
eth_getLogsfor reliable event queries:
curl "https://relayer.specterchain.com/api/indexer?event=CommitmentInserted&fromBlock=0&toBlock=latest"
- For real-time event monitoring, subscribe via WebSocket if supported, or poll the indexer API at regular intervals.
- If you must use
eth_getLogs, limit the block range to small windows (100-500 blocks) and retry on empty results.
eth_getTransactionReceipt Parse Errors
Symptoms:
- Calls to
eth_getTransactionReceiptreturn malformed or unparseable responses for certain transactions. ethers.jsorviemthrow errors when processing receipts.- Contract deployment receipts fail to parse the
contractAddressfield.
Cause: The Cosmos EVM module's transaction receipt encoding can differ from standard Ethereum in edge cases, particularly for contract creation transactions and transactions involving precompile calls.
Solution:
- For contract deployments, use computed addresses instead of relying on the receipt's
contractAddressfield:
import { ethers } from "ethers";
// For CREATE deployments: compute from sender + nonce
const deployerAddress = "0xYourDeployerAddress";
const nonce = await provider.getTransactionCount(deployerAddress);
const computedAddress = ethers.getCreateAddress({
from: deployerAddress,
nonce: nonce,
});
// For CREATE2 deployments: compute from factory + salt + initCodeHash
const computedAddress = ethers.getCreate2Address(
factoryAddress,
salt,
initCodeHash
);
- For general receipt parsing, wrap receipt fetching in a try-catch and fall back to the RPC's raw response if the library parser fails:
try {
const receipt = await provider.getTransactionReceipt(txHash);
} catch (e) {
// Fall back to raw RPC call
const rawReceipt = await provider.send("eth_getTransactionReceipt", [txHash]);
// Parse manually
}
Balance Shows 0 in the Webapp
Symptoms:
- The webapp shows a balance of
0for all tokens. - The faucet confirms a successful drip, but the balance does not update.
- MetaMask shows the correct balance, but the webapp does not.
Cause: The webapp's config.js has the wrong Chain ID configured. If chainConfig.chainId is set to the deprecated 47474 instead of 5446, the webapp connects to the wrong chain or fails to match the wallet's chain, resulting in zero balances.
Solution:
- Open
config.jsin the webapp source. - Verify that
chainConfig.chainIdis5446:export const chainConfig = {
chainId: 5446, // NOT 47474
// ...
}; - Also verify
chainIdHexis"0x1546". - Rebuild and redeploy the webapp.
- If using a custom deployment, check that the RPC URL in
config.jspoints totestnet.specterchain.com.
AutoCliOpts Panic in app.go
Symptoms:
When starting the Specter node, it panics during initialization with an error referencing AutoCliOpts and address codec:
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation]
goroutine 1 [running]:
github.com/cosmos/cosmos-sdk/server.AddCommands (...)
autocli.go:XX
Cause: The AutoCliOpts function in app.go is missing the address codec configuration. The Cosmos SDK's autocli module requires a properly initialized AddressCodec to encode and decode Bech32 addresses. If the codec is nil, it causes a nil pointer dereference at startup.
Solution:
Ensure that the AutoCliOpts() method on the app struct returns a properly configured AddressCodec:
func (app *SpecterApp) AutoCliOpts() autocli.AppOptions {
modules := make(map[string]appmodule.AppModule, 0)
for _, m := range app.ModuleManager.Modules {
if moduleWithName, ok := m.(module.HasName); ok {
moduleName := moduleWithName.Name()
if appModule, ok := m.(appmodule.AppModule); ok {
modules[moduleName] = appModule
}
}
}
return autocli.AppOptions{
Modules: modules,
AddressCodec: authcodec.NewBech32Codec(sdk.GetConfig().GetBech32AccountAddrPrefix()),
ValidatorAddressCodec: authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ValidatorAddrPrefix()),
ConsensusAddressCodec: authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ConsensusAddrPrefix()),
}
}
The key fix is including AddressCodec, ValidatorAddressCodec, and ConsensusAddressCodec in the returned AppOptions. Without these, any CLI command that formats addresses will panic.
General Debugging Tips
Verify Chain Connectivity
# Check if the RPC is responding
curl -s -X POST https://testnet.specterchain.com \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}'
# Expected: {"jsonrpc":"2.0","id":1,"result":"0x1546"}
Check Contract Deployment
# Verify a contract exists at an address
curl -s -X POST https://testnet.specterchain.com \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_getCode","params":["0x908aA11Dc9F2e2C3F69892acaDE112e831c0a14a","latest"],"id":1}' \
| python3 -c "import sys,json; r=json.load(sys.stdin)['result']; print('Deployed' if len(r) > 2 else 'No code')"
Inspect a Transaction
# Get transaction details
curl -s -X POST https://testnet.specterchain.com \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_getTransactionByHash","params":["0xYourTxHash"],"id":1}'
Check Nullifier Status
import { ethers } from "ethers";
const provider = new ethers.JsonRpcProvider("https://testnet.specterchain.com");
const nullifierRegistry = new ethers.Contract(
"0xaadb9c3394835B450023daA91Ad5a46beA6e43a1",
["function isSpent(bytes32 nullifier) view returns (bool)"],
provider
);
const spent = await nullifierRegistry.isSpent(nullifierHash);
console.log("Nullifier spent:", spent);
Verify Merkle Root
const commitmentTree = new ethers.Contract(
"0xE29DD14998f6FE8e7862571c883090d14FE29475",
["function getRoot() view returns (bytes32)"],
provider
);
const root = await commitmentTree.getRoot();
console.log("Current Merkle root:", root);