Troubleshooting¶
Common issues and how to resolve them.
Node won't connect to peers¶
Symptoms: getPeerCount() returns 0, no messages received.
Check seed connectivity:
Possible causes:
- Firewall: Outbound TCP to port 9876 must be allowed
- DNS: Ensure
node1.missylabs.cometc. resolve correctly - Custom seeds: If using
--seedsor--no-seeds, verify the multiaddr format is correct - NAT: If behind strict NAT, ensure WebSocket and circuit relay are enabled (they are by default)
Messages are not being received¶
Symptoms: onTag handler never fires, but node has peers.
Check trust policy: Leyline uses deny-first trust. You must explicitly allow senders:
Check tag subscriptions: You only receive messages for tags you're subscribed to:
Check spam filter: If the sender is hitting rate limits, their messages are blocked:
// The default is 60 messages/minute/sender
// Check if sender is being rate limited by reviewing local ledger for "blocked" actions
Service discovery returns no results¶
Possible causes:
- TTL expired: Services expire after their TTL (default 5 minutes). The advertising node may have gone offline.
- Trust policy: Discovery results are filtered by trust. Allow the provider's public key.
- Tag mismatch: Discovery uses OR matching on tags. Make sure at least one tag matches.
- No peers: If you have no connected peers, there's nobody to query.
Ledger verification fails¶
Symptoms: ledger.verify() returns false.
This means the hash chain has been corrupted — an entry's prevHash doesn't match the previous entry's hash.
Possible causes:
- Unclean shutdown (killed with SIGKILL, power loss)
- Disk corruption
- Manual editing of LevelDB files
Recovery: The local ledger is an audit trail. If corrupted, you can reset it:
For the shared ledger, entries will be re-synced from peers after reset:
Direct messages not delivering¶
Check:
- Peer connected? Direct messages require either a direct connection or a relay path to the target
- Trust? DMs go through the trust policy — allow the sender
- Correct peer ID? The
targetPeerIdmust be the recipient's libp2p peer ID, not their public key - Encryption? If providing
recipientPubkeyHex, ensure it's the correct 64-char hex key
High memory usage¶
The primary memory consumers:
| Component | Default | Tuning |
|---|---|---|
| Dedup cache | 100,000 entries | Lower maxSeenMessages in config |
| Peer table | 500 peers max | Lower maxPeers in PeerExchange |
| Rate limit windows | Per-sender timestamps | Ephemeral, cleans up automatically |
const node = new MagicNode({
maxSeenMessages: 10_000, // Reduce dedup cache for low-memory environments
});
Identity file issues¶
"Permission denied" on identity.json:
The file should be mode 0600. Fix:
"Malformed JSON" on startup:
The identity file is corrupt. Delete it and restart — a new keypair will be generated:
Peer exchange not growing the mesh¶
The peer exchange runs every 30 seconds. If the peer table stays small:
- Few peers on network: If only seed nodes are online, the table will be small
- Stale peers: Peers older than 30 minutes are pruned. If peers connect briefly and leave, they'll be evicted
- Max peers: Table is capped at 500. If reached, oldest 10% are evicted on each add
Checking what's happening¶
Enable verbose logging by looking at the node's events:
const node = new MagicNode({
dataDir: './data',
subscribedTags: ['skill:code'],
}, {
onMessage: (msg, tag) => {
console.log(`[MSG] ${tag} from ${Buffer.from(msg.senderPubkey).toString('hex').slice(0, 16)}...`);
},
onPeerConnected: (peerId) => {
console.log(`[PEER+] ${peerId}`);
},
onPeerDisconnected: (peerId) => {
console.log(`[PEER-] ${peerId}`);
},
});
Check the local ledger for blocked messages: