Skip to content

fix(meshcore): clarify LPP telemetry WARN and stop pubkey nodeNum log spam#3680

Merged
Yeraze merged 1 commit into
mainfrom
fix/meshcore-telemetry-log-clarity
Jun 23, 2026
Merged

fix(meshcore): clarify LPP telemetry WARN and stop pubkey nodeNum log spam#3680
Yeraze merged 1 commit into
mainfrom
fix/meshcore-telemetry-log-clarity

Conversation

@Yeraze

@Yeraze Yeraze commented Jun 23, 2026

Copy link
Copy Markdown
Owner

Summary

Two small MeshCore telemetry log-clarity fixes.

#3676 — ambiguous LPP timeout WARN

For repeater-like targets the scheduler runs two independent telemetry paths: status (requestNodeStatus) and LPP (requestRemoteTelemetry). A common, non-fatal LPP timeout logged:

[WARN] requestRemoteTelemetry(...) failed: timeout
[INFO] Wrote 16 telemetry rows ... (status:16)

which reads like a hard failure even though the status path succeeded. The WARN now names the path explicitly — requestRemoteTelemetry (LPP) (...) failed: ... — so operators can tell which path timed out. The sibling threw WARN is labeled the same way.

#3677rejecting out-of-range nodeNum 6.027...e+76 spam

GET /api/telemetry/:nodeId unconditionally ran parseInt(nodeId, 16) and called getNode to read the private-position flag. MeshCore peers arrive here as a 64-hex public key, which overflows parseInt to ~6e+76 and trips NodesRepository.getNode's out-of-range guard on every poll (the MeshCore Info view auto-refreshes). The lookup is now skipped for 64-hex ids — they have no Meshtastic position-override semantics, so isPrivate is simply false, and the warning stops.

Testing

  • Added a regression test asserting getNode is not called for a 64-hex pubkey id.
  • Full Vitest suite: 7337 passed, 0 failed.

Closes #3676
Closes #3677

🤖 Generated with Claude Code

Two log-clarity fixes for MeshCore telemetry:

- #3676: requestRemoteTelemetry() WARN now names the LPP path explicitly
  ("requestRemoteTelemetry (LPP)") so it isn't confused with the separate
  status/stats request that runs alongside it for repeater-like targets.
  An LPP timeout is common and non-fatal; the status path is unaffected.

- #3677: GET /api/telemetry/:nodeId skips the getNode lookup for 64-hex
  MeshCore public keys. Previously parseInt overflowed to ~6e+76 and tripped
  NodesRepository.getNode's out-of-range guard on every poll, spamming
  '[WARN] rejecting out-of-range nodeNum 6.027...e+76'. MeshCore peers have
  no Meshtastic position-override semantics, so isPrivate is simply false.

Adds a regression test asserting getNode is not called for a pubkey id.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBLhGGNh35oMwTL53va1Y5
@github-actions

github-actions Bot commented Jun 23, 2026

Copy link
Copy Markdown

Claude finished @Yeraze's task —— View job


PR Review

  • Read changed files
  • Review code quality and correctness
  • Assess test coverage
  • Post final review

Both fixes are clean and well-targeted. Here's the detailed breakdown:

meshcoreManager.ts — LPP WARN label (#3676)

src/server/meshcoreManager.ts:3580-3593

The (LPP) tag added to both logger.warn lines is a minimal, effective change. No logic is altered — just the log message. The comment block above is clear about the intent (non-fatal, the status path is unaffected). No issues here.

Minor nit: the threw variant logs as threw: with error passed as the second argument to logger.warn, which formats differently from the failed: path which interpolates the error message into the string. This is pre-existing behavior and not introduced by this PR, so not a blocker.

telemetryRoutes.ts — 64-hex pubkey bypass (#3677)

src/server/routes/telemetryRoutes.ts:64-69

const nodeNum = /^[0-9a-fA-F]{64}$/.test(nodeId)
  ? NaN
  : parseInt(nodeId.replace('!', ''), 16);
const node = isValidNodeNum(nodeNum)
  ? await databaseService.nodes.getNode(nodeNum, telSourceId)
  : null;

The fix is correct. A 64-hex MeshCore public key has no Meshtastic nodeNum semantics, and isValidNodeNum(NaN)false, so getNode is correctly skipped and isPrivate defaults to false.

One observation worth noting: the regex ^[0-9a-fA-F]{64}$ is case-sensitive to length=64 only. If MeshCore ever produces public keys in a different encoding (e.g. prefixed, base64), the guard won't catch them. But for the current protocol, 64 lowercase hex chars is the documented format and this is sufficient.

Potential edge case: a Meshtastic nodeId like !<8-hex> with trailing garbage would still fall through to parseInt (not matching the 64-hex pattern), but parseInt with the ! stripped handles that gracefully anyway. No regression risk.

telemetryRoutes.test.ts — Test coverage (#3677)

src/server/routes/telemetryRoutes.test.ts:81-92

The regression test is exactly right:

  • Uses 'a'.repeat(64) to produce a valid 64-hex pubkey
  • Asserts getNode was not called
  • Asserts the response is still 200 with data (i.e., telemetry still flows normally)

The test does not mock databaseService.nodes.getNode, which is fine — vi.fn() returns undefined by default, and the test is asserting it's never called. The explicit not.toHaveBeenCalled() assertion is the meaningful one.

Summary

Area Finding
Code quality ✅ Clean, minimal, well-commented changes
Correctness ✅ Both fixes are logically sound
Performance ✅ Eliminates a wasted DB round-trip per poll cycle
Security ✅ No new attack surface introduced; isPrivate defaults conservatively to false
Test coverage ✅ Regression test covers the exact fix; existing tests unaffected

No blocking issues. Ready to merge.

@Yeraze Yeraze merged commit f9c0880 into main Jun 23, 2026
19 checks passed
@Yeraze Yeraze deleted the fix/meshcore-telemetry-log-clarity branch June 23, 2026 22:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[SUPPORT] NodesRepository.getNode [BUG] Meshcore Telemetri failing

1 participant