Skip to content

Commit 1fa88f6

Browse files
staticoclaude
andcommitted
Fix error code mapping for all routing errors
The issue was that Mesh.Routing_Error enum reverse lookup by number wasn't working for all error codes (especially 32-38). This caused "error 38" to show instead of "RATE_LIMIT_EXCEEDED". Created ROUTING_ERROR_NAMES mapping with all 17 error codes from mesh.proto: - 0-9: NONE, NO_ROUTE, GOT_NAK, TIMEOUT, NO_INTERFACE, MAX_RETRANSMIT, NO_CHANNEL, TOO_LARGE, NO_RESPONSE, DUTY_CYCLE_LIMIT - 32-38: BAD_REQUEST, NOT_AUTHORIZED, PKI_FAILED, PKI_UNKNOWN_PUBKEY, ADMIN_BAD_SESSION_KEY, ADMIN_PUBLIC_KEY_UNAUTHORIZED, RATE_LIMIT_EXCEEDED Updated both DMPanel and ChatPanel formatErrorReason functions to use exact enum name matches first, then fallback to substring matches. Now all error codes correctly map to human-readable labels: - error 38 → "rate limited" - error 37 → "admin no auth" - etc. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent 6ee29ae commit 1fa88f6

3 files changed

Lines changed: 64 additions & 31 deletions

File tree

src/ui/App.tsx

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,27 @@ import { Logger } from "../logger";
3232

3333
const BROADCAST_ADDR = 0xFFFFFFFF;
3434

35+
// Map error codes to enum names for routing errors
36+
const ROUTING_ERROR_NAMES: Record<number, string> = {
37+
0: "NONE",
38+
1: "NO_ROUTE",
39+
2: "GOT_NAK",
40+
3: "TIMEOUT",
41+
4: "NO_INTERFACE",
42+
5: "MAX_RETRANSMIT",
43+
6: "NO_CHANNEL",
44+
7: "TOO_LARGE",
45+
8: "NO_RESPONSE",
46+
9: "DUTY_CYCLE_LIMIT",
47+
32: "BAD_REQUEST",
48+
33: "NOT_AUTHORIZED",
49+
34: "PKI_FAILED",
50+
35: "PKI_UNKNOWN_PUBKEY",
51+
36: "ADMIN_BAD_SESSION_KEY",
52+
37: "ADMIN_PUBLIC_KEY_UNAUTHORIZED",
53+
38: "RATE_LIMIT_EXCEEDED",
54+
};
55+
3556
type AppMode = "packets" | "nodes" | "chat" | "dm" | "config" | "log" | "meshview";
3657

3758
export interface ChannelInfo {
@@ -500,7 +521,7 @@ export function App({ address, packetStore, nodeStore, skipConfig = false, skipN
500521
if (routing.variant?.case === "errorReason" && routing.variant.value !== undefined) {
501522
const isAck = routing.variant.value === Mesh.Routing_Error.NONE;
502523
const newStatus: db.MessageStatus = isAck ? "acked" : "error";
503-
const errorReason = isAck ? undefined : (Mesh.Routing_Error[routing.variant.value] || `error_${routing.variant.value}`);
524+
const errorReason = isAck ? undefined : (ROUTING_ERROR_NAMES[routing.variant.value] || `error_${routing.variant.value}`);
504525
Logger.info("App", "Received routing response", {
505526
requestId: packet.requestId,
506527
from: mp.from,

src/ui/components/ChatPanel.tsx

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -378,22 +378,28 @@ function MessageRow({ message, nodeStore, isOwn, isSelected, width, meshViewConf
378378
const formatErrorReason = (reason?: string): string => {
379379
if (!reason) return "failed";
380380
const lowerReason = reason.toLowerCase().replace(/_/g, " ");
381-
if (lowerReason.includes("max retransmit")) return "max retries";
382-
if (lowerReason.includes("no route")) return "no route";
383-
if (lowerReason.includes("got nak")) return "rejected";
384-
if (lowerReason.includes("timeout")) return "timeout";
385-
if (lowerReason.includes("no interface")) return "no interface";
386-
if (lowerReason.includes("too large")) return "too large";
387-
if (lowerReason.includes("no channel")) return "no channel";
388-
if (lowerReason.includes("duty cycle")) return "duty limit";
389-
if (lowerReason.includes("bad request")) return "bad request";
390-
if (lowerReason.includes("not authorized")) return "no auth";
391-
if (lowerReason.includes("no response")) return "no response";
392-
if (lowerReason.includes("pki")) return "pki failed";
393-
if (lowerReason.includes("public key")) return "unknown key";
394-
if (lowerReason.includes("admin") && lowerReason.includes("session")) return "bad session";
395-
if (lowerReason.includes("admin") && lowerReason.includes("unauthorized")) return "admin no auth";
381+
382+
// Direct enum name matches
383+
if (lowerReason === "max retransmit") return "max retries";
384+
if (lowerReason === "no route") return "no route";
385+
if (lowerReason === "got nak") return "rejected";
386+
if (lowerReason === "timeout") return "timeout";
387+
if (lowerReason === "no interface") return "no interface";
388+
if (lowerReason === "too large") return "too large";
389+
if (lowerReason === "no channel") return "no channel";
390+
if (lowerReason === "no response") return "no response";
391+
if (lowerReason === "duty cycle limit") return "duty limit";
392+
if (lowerReason === "bad request") return "bad request";
393+
if (lowerReason === "not authorized") return "no auth";
394+
if (lowerReason === "pki failed") return "pki failed";
395+
if (lowerReason === "pki unknown pubkey") return "unknown key";
396+
if (lowerReason === "admin bad session key") return "bad session";
397+
if (lowerReason === "admin public key unauthorized") return "admin no auth";
398+
if (lowerReason === "rate limit exceeded") return "rate limited";
399+
400+
// Fallback to substring matches for legacy reasons
396401
if (lowerReason.includes("rate limit")) return "rate limited";
402+
397403
return lowerReason.slice(0, 12);
398404
};
399405

src/ui/components/DMPanel.tsx

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -245,22 +245,28 @@ function MessageRow({ message, nodeStore, isOwn, isSelected, textWidth, meshView
245245
const formatErrorReason = (reason?: string): string => {
246246
if (!reason) return "failed";
247247
const lowerReason = reason.toLowerCase().replace(/_/g, " ");
248-
if (lowerReason.includes("max retransmit")) return "max retries";
249-
if (lowerReason.includes("no route")) return "no route";
250-
if (lowerReason.includes("got nak")) return "rejected";
251-
if (lowerReason.includes("timeout")) return "timeout";
252-
if (lowerReason.includes("no interface")) return "no interface";
253-
if (lowerReason.includes("too large")) return "too large";
254-
if (lowerReason.includes("no channel")) return "no channel";
255-
if (lowerReason.includes("duty cycle")) return "duty limit";
256-
if (lowerReason.includes("bad request")) return "bad request";
257-
if (lowerReason.includes("not authorized")) return "no auth";
258-
if (lowerReason.includes("no response")) return "no response";
259-
if (lowerReason.includes("pki")) return "pki failed";
260-
if (lowerReason.includes("public key")) return "unknown key";
261-
if (lowerReason.includes("admin") && lowerReason.includes("session")) return "bad session";
262-
if (lowerReason.includes("admin") && lowerReason.includes("unauthorized")) return "admin no auth";
248+
249+
// Direct enum name matches
250+
if (lowerReason === "max retransmit") return "max retries";
251+
if (lowerReason === "no route") return "no route";
252+
if (lowerReason === "got nak") return "rejected";
253+
if (lowerReason === "timeout") return "timeout";
254+
if (lowerReason === "no interface") return "no interface";
255+
if (lowerReason === "too large") return "too large";
256+
if (lowerReason === "no channel") return "no channel";
257+
if (lowerReason === "no response") return "no response";
258+
if (lowerReason === "duty cycle limit") return "duty limit";
259+
if (lowerReason === "bad request") return "bad request";
260+
if (lowerReason === "not authorized") return "no auth";
261+
if (lowerReason === "pki failed") return "pki failed";
262+
if (lowerReason === "pki unknown pubkey") return "unknown key";
263+
if (lowerReason === "admin bad session key") return "bad session";
264+
if (lowerReason === "admin public key unauthorized") return "admin no auth";
265+
if (lowerReason === "rate limit exceeded") return "rate limited";
266+
267+
// Fallback to substring matches for legacy reasons
263268
if (lowerReason.includes("rate limit")) return "rate limited";
269+
264270
return lowerReason.slice(0, 12);
265271
};
266272

0 commit comments

Comments
 (0)