# How to Debug Issues in BitChat: A Complete Guide to Mesh Messaging Troubleshooting

> Debug BitChat issues with our complete guide. Learn to troubleshoot Bluetooth mesh, Noise encryption, and Nostr relay problems by inspecting transport events and logs.

- Repository: [permissionlesstech/bitchat](https://github.com/permissionlesstech/bitchat)
- Tags: how-to-guide
- Published: 2026-08-01

---

**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**.

```swift
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`](https://github.com/permissionlesstech/bitchat/blob/main/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`.

```swift
// 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`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Services/Transport.swift) — transport abstraction and event definitions
- [`bitchat/Services/BLEService.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Services/BLEService.swift) — Bluetooth mesh implementation

**Debug steps:**

1. **Set a breakpoint** in `BLEService.startServices()` to verify the mesh stack starts.
2. **Watch `TransportEvent` flow** via `BitchatDelegate.receiveTransportEvent` (see the `extension BitchatDelegate` at the bottom of [`Transport.swift`](https://github.com/permissionlesstech/bitchat/blob/main/Transport.swift)).
3. **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`.

```swift
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`](https://github.com/permissionlesstech/bitchat/blob/main/NoiseSessionTests.swift), [`NoiseSecurityValidatorTests.swift`](https://github.com/permissionlesstech/bitchat/blob/main/NoiseSecurityValidatorTests.swift)) to confirm cryptographic primitives work on your device.
- Inspect `noiseSessionPublicKeyData(for:)` in `Transport` — this defaults to `nil` for non‑mesh transports.

**Source:** `NoiseSessionManager` — [`bitchat/Noise/NoiseSessionManager.swift`](https://github.com/permissionlesstech/bitchat/blob/main/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.

```swift
// Log pending message count on a relay
SecureLogger.debug(
    "Relay \(relayURL) pending queue = \(manager.debugPendingMessageQueueCount)",
    category: .session)

```

**Debug steps:**

1. Enable `debugPendingMessageQueueCount` checks in test builds only.
2. Use the **performance gate script** to catch regressions affecting relay throughput:

```bash
swift test --filter PerformanceBaselineTests
scripts/check-perf-floors.sh path/to/test-output.log

```

**Source:** `NostrRelayManagerTests` — [`bitchatTests/Services/NostrRelayManagerTests.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchatTests/Services/NostrRelayManagerTests.swift)

## Run the Complete Test Suite

The repository ships with a comprehensive SwiftPM test suite. Run it with:

```bash

# 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 `TransportPeerSnapshot` objects to confirm nicknames, connectivity flags, and `isVerified` status.
- **Memory Graph**: Detect orphaned media files via `PrivateMediaDeletionPersisting` callbacks ([`Transport.swift`](https://github.com/permissionlesstech/bitchat/blob/main/Transport.swift), lines 99‑110).
- **Console Filter**: Filter Xcode console on `session` or `mesh` categories 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:**

1. **Check `Transport.delegate`** — must be non‑nil for event propagation.
2. **Handle `peerListUpdated`** — missing UI updates create "ghost peer" symptoms.
3. **Refresh stale Noise sessions** — call `triggerHandshake(with:)` when peers reappear.

## Practical Debug Examples

### Enable Debug Logging Across All Categories

```swift
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

```swift
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

```bash

# 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 = .debug`** to capture detailed diagnostic output across all BitChat subsystems.
- **Monitor `TransportEvent` flow** through `BitchatDelegate.receiveTransportEvent` to trace Bluetooth mesh activity.
- **Validate Noise handshakes** via `installNoiseSessionCallbacks` and the `Noise*Tests` suite.
- **Inspect relay queues** using `debugPendingMessageQueueCount` when debugging Nostr fallback behavior.
- **Run [`scripts/check-perf-floors.sh`](https://github.com/permissionlesstech/bitchat/blob/main/scripts/check-perf-floors.sh)** after any algorithmic change to prevent performance regressions.
- **Use Xcode's View Debugger and Memory Graph** to inspect `TransportPeerSnapshot` state 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`](https://github.com/permissionlesstech/bitchat/blob/main/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`](https://github.com/permissionlesstech/bitchat/blob/main/NoiseSessionTests.swift) and [`NoiseSecurityValidatorTests.swift`](https://github.com/permissionlesstech/bitchat/blob/main/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`](https://github.com/permissionlesstech/bitchat/blob/main/scripts/check-perf-floors.sh) gate, useful when iterating on time‑consuming tests. Remove this flag before committing to catch throughput regressions.