How to Debug Issues in BitChat: A Complete Guide to Mesh Messaging Troubleshooting
Enable SecureLogger.minimumLevel = .debug and inspect TransportEvent flow through BitchatDelegate.receiveTransportEvent to diagnose Bluetooth mesh, Noise encryption, and Nostr relay issues in BitChat.
BitChat is a dual‑transport, peer‑to‑peer messenger that blends a local Bluetooth mesh with the global Nostr network. Because it combines real‑time mesh routing, Noise‑based encryption, and asynchronous Nostr delivery, debugging issues in BitChat requires a systematic approach across multiple architectural layers. This guide covers the exact tools, source files, and techniques used by the permissionlesstech/bitchat development team.
Enable Verbose Logging with SecureLogger
BitChat uses the SecureLogger wrapper around Apple's OSLog. The most useful level for troubleshooting is debug.
import BitLogger
// Turn on debug logging for a specific category (e.g., .session)
SecureLogger.minimumLevel = .debug
SecureLogger.debug("Starting mesh handshake", category: .session)
The logger automatically drops debug messages in production builds, so you can leave these calls in code without affecting release performance.
Source: SecureLogger implementation — localPackages/BitLogger/Sources/SecureLogger.swift
Inspect the Transport Layer
All mesh activity funnels through the Transport protocol. The concrete implementation is BLEService, which conforms to many helper protocols including MeshFileTransferring and MeshVoiceStreaming.
// Example: Log a peer's connection state change
func transport(_ transport: Transport, didConnect peerID: PeerID) {
SecureLogger.debug("Peer \(peerID) connected", category: .session)
}
Key source files:
bitchat/Services/Transport.swift— transport abstraction and event definitionsbitchat/Services/BLEService.swift— Bluetooth mesh implementation
Debug steps:
- Set a breakpoint in
BLEService.startServices()to verify the mesh stack starts. - Watch
TransportEventflow viaBitchatDelegate.receiveTransportEvent(see theextension BitchatDelegateat the bottom ofTransport.swift). - Check peer snapshots (
peerSnapshotsUpdated) to confirm the device sees nearby peers.
Verify Noise Handshake Authentication
Noise sessions secure mesh traffic. The handshake lifecycle is exposed through callbacks installed via installNoiseSessionCallbacks.
transport.installNoiseSessionCallbacks(
onPeerAuthenticated: { peer, fingerprint in
SecureLogger.debug("Authenticated \(peer) → \(fingerprint)", category: .session)
},
onHandshakeRequired: { peer in
SecureLogger.debug("Handshake needed for \(peer)", category: .session)
})
Debug steps:
- Run the Noise unit tests (
NoiseSessionTests.swift,NoiseSecurityValidatorTests.swift) to confirm cryptographic primitives work on your device. - Inspect
noiseSessionPublicKeyData(for:)inTransport— this defaults tonilfor non‑mesh transports.
Source: NoiseSessionManager — bitchat/Noise/NoiseSessionManager.swift
Test Nostr Relay Behavior
When the Bluetooth mesh is unavailable, BitChat falls back to Nostr. The NostrRelayManager handles subscriptions, outgoing queues, and duplicate‑event filtering.
// Log pending message count on a relay
SecureLogger.debug(
"Relay \(relayURL) pending queue = \(manager.debugPendingMessageQueueCount)",
category: .session)
Debug steps:
- Enable
debugPendingMessageQueueCountchecks in test builds only. - Use the performance gate script to catch regressions affecting relay throughput:
swift test --filter PerformanceBaselineTests
scripts/check-perf-floors.sh path/to/test-output.log
Source: NostrRelayManagerTests — bitchatTests/Services/NostrRelayManagerTests.swift
Run the Complete Test Suite
The repository ships with a comprehensive SwiftPM test suite. Run it with:
# macOS debug build (no signing required)
xcodebuild -project bitchat.xcodeproj -scheme "bitchat (macOS)" \
-configuration Debug CODE_SIGNING_ALLOWED=NO test
Key test groups:
| Test Group | What It Validates |
|---|---|
ChatViewModelTests |
Message flow, UI state updates |
BLEQueueContractTests |
Mesh queue invariants |
SecureIdentityStateManagerTests |
Identity key handling |
PerformanceBaselineTests |
Raw throughput of critical algorithms |
Noise*Tests |
End‑to‑end encryption correctness |
Set BITCHAT_SKIP_PERF_BASELINES=1 to bypass performance gates when debugging time‑consuming tests.
Use Xcode Diagnostics Effectively
- View Debugger: Inspect
TransportPeerSnapshotobjects to confirm nicknames, connectivity flags, andisVerifiedstatus. - Memory Graph: Detect orphaned media files via
PrivateMediaDeletionPersistingcallbacks (Transport.swift, lines 99‑110). - Console Filter: Filter Xcode console on
sessionormeshcategories to focus relevant logs.
Diagnose Crashes and Unexpected Behavior
When BitChat crashes, the stack trace often points to fatal errors in BLEService conformances. The Transport protocol supplies default no‑op implementations for optional features — verify you haven't overridden them with buggy code.
Critical checklist:
- Check
Transport.delegate— must be non‑nil for event propagation. - Handle
peerListUpdated— missing UI updates create "ghost peer" symptoms. - Refresh stale Noise sessions — call
triggerHandshake(with:)when peers reappear.
Practical Debug Examples
Enable Debug Logging Across All Categories
import BitLogger
func configureLogging() {
SecureLogger.minimumLevel = .debug
let categories: [OSLog] = [.session, .keychain, .network, .noise]
categories.forEach { cat in
SecureLogger.debug("Logging enabled for category \(cat)", category: cat)
}
}
Dump Peer Connection State
func dumpPeers(_ transport: Transport) {
let snapshots = transport.currentPeerSnapshots()
for snap in snapshots {
SecureLogger.debug(
"""
Peer: \(snap.peerID)
Nick: \(snap.nickname)
Connected: \(snap.isConnected)
Verified: \(snap.isVerified)
""",
category: .session)
}
}
Targeted Performance Test with Gate
# Run only mesh routing performance test
swift test --filter MeshRoutingPerformanceTests
# Ensure no regression occurred
scripts/check-perf-floors.sh .build/debug/TestOutput.log
Summary
- Enable
SecureLogger.minimumLevel = .debugto capture detailed diagnostic output across all BitChat subsystems. - Monitor
TransportEventflow throughBitchatDelegate.receiveTransportEventto trace Bluetooth mesh activity. - Validate Noise handshakes via
installNoiseSessionCallbacksand theNoise*Testssuite. - Inspect relay queues using
debugPendingMessageQueueCountwhen debugging Nostr fallback behavior. - Run
scripts/check-perf-floors.shafter any algorithmic change to prevent performance regressions. - Use Xcode's View Debugger and Memory Graph to inspect
TransportPeerSnapshotstate and detect resource leaks.
Frequently Asked Questions
How do I enable debug logging in a release build of BitChat?
You cannot. According to the SecureLogger implementation in localPackages/BitLogger/Sources/SecureLogger.swift, debug logs are automatically stripped from production builds. This is by design — use a Debug build configuration or run via Xcode to capture verbose output.
Why are my peers not appearing in the BitChat UI?
Check three things: (1) verify BLEService.startServices() executes without error, (2) confirm Transport.delegate is set to receive peerListUpdated events, and (3) inspect TransportPeerSnapshot objects via the View Debugger to validate isConnected and isVerified flags. Missing UI updates often indicate the delegate callback isn't wired correctly.
What causes Noise handshake failures in BitChat?
The most common causes are key mismatches and stale session state. Use triggerHandshake(with:) to force re‑authentication when a peer becomes reachable again. Run NoiseSessionTests.swift and NoiseSecurityValidatorTests.swift to isolate whether the issue is cryptographic or network‑related.
How do I skip performance baseline checks during development?
Set the environment variable BITCHAT_SKIP_PERF_BASELINES=1 when running tests. This bypasses the scripts/check-perf-floors.sh gate, useful when iterating on time‑consuming tests. Remove this flag before committing to catch throughput regressions.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →