Skip to content

Surface the reason when Prometheus metrics are unavailable - #2273

Draft
s1ckoleg wants to merge 4 commits into
freelensapp:mainfrom
s1ckoleg:surface-prometheus-metrics-errors
Draft

Surface the reason when Prometheus metrics are unavailable#2273
s1ckoleg wants to merge 4 commits into
freelensapp:mainfrom
s1ckoleg:surface-prometheus-metrics-errors

Conversation

@s1ckoleg

@s1ckoleg s1ckoleg commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Problem

When Prometheus metrics cannot be fetched, all detail-view charts show only the generic "Metrics not available at the moment". The real cause is invisible:

  • The POST /api/metrics route swallows every failure and returns HTTP 200 with {}, so the renderer cannot distinguish a fetch error from an empty result.
  • The main-process log line drops error.cause, so even the logs only say Error: No Prometheus service found or Error: Metrics not available with no HTTP status and no Kubernetes error message (e.g. the RBAC Forbidden body).
  • If the renderer metrics request rejects unexpectedly, the chart hangs on a spinner forever: the asyncComputed wrapper in create-time-ranged-metrics.ts has no rejection handler, so pending never resolves.

In practice this makes RBAC-restricted clusters (users without services list / services/proxy permissions) undiagnosable from inside the app: auto-detection fails, manual configuration fails, and the UI gives no hint why.

Related: #1078, #1566.

Changes

One commit per independent fix:

  1. Preserve the original Kubernetes API error when Prometheus service discovery fails — the re-throws in provider.ts now attach { cause }, so the Kubernetes client error (with its HTTP status) survives the chain instead of being flattened into a string.
  2. Log the real cause when the metrics route fails — new metrics-error-classification.ts classifies failures (not-found / access-denied / error) by walking the cause chain, and the warn log now includes the serialized cause chain (HTTP statuses, per-provider detection errors) instead of only the outer message.
  3. Fix metrics charts hanging on a spinner forever after a failed requestcreate-time-ranged-metrics.ts now catches request rejections (always resolving, since asyncComputed has no rejection handler) and exposes the failure as an observable error alongside value/pending.
  4. Surface the reason when Prometheus metrics are unavailable — the route returns a structured MetricsErrorInfo with a proper status code (503 not-found / 403 access-denied / carried status otherwise), and NoMetrics shows a reason-specific message ("No Prometheus service was found for this cluster." / "Access to Prometheus metrics was denied.") with an "Open cluster settings" link and the raw detail in the tooltip. The generic no-data state renders exactly as before. All direct requestMetrics call sites were audited and now handle rejection (cluster overview, nodes list) by falling back to the previous empty-metrics behavior.

Compatibility

The successful response shape of POST /api/metrics is unchanged. Extension callers of Renderer.K8sApi.requestMetrics keep resolving with the same data on success; on failure they get a rejected promise (carrying a structured error body) instead of a silently empty object.

Testing

  • New unit tests: error classification (main), metrics route error responses and logging payload, renderer error classifier, create-time-ranged-metrics rejection/recovery, NoMetrics states and settings-link navigation, JsonApiErrorParsed.data accessor, cluster overview metrics fallback.
  • Full @freelensapp/core suite: 2405 passed / 27 skipped (baseline before this branch: 2385 / 27), no regressions; full monorepo type-check clean; biome/trunk clean.

Remaining before marking ready

  • Manual verification in the running app against a cluster where metrics fail (RBAC-restricted or no Prometheus): pod detail should show the reason and the settings link instead of the generic message, and lens.log should contain the serialized cause (e.g. the Kubernetes Forbidden details).

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.

1 participant