MHSanaei/3x-ui · error

invalid metric (unknown metric)

Error message

invalid metric (unknown metric)

What it means

ServerController.getXrayMetricsHistoryBucket validates its metric path parameter against service.XrayMetricKeys — a different allowlist from the system metrics — and returns 'invalid metric' (detail 'unknown metric') on mismatch. These keys describe Xray child-process counters exposed by the xray metrics service, so the accepted names depend on what that service tracks.

Source

Thrown at internal/web/controller/server.go:157

	if !slices.Contains(service.SystemMetricKeys, metric) {
		jsonMsg(c, "invalid metric", fmt.Errorf("unknown metric"))
		return
	}
	bucket, ok := parseHistoryBucket(c)
	if !ok {
		return
	}
	jsonObj(c, a.serverService.AggregateSystemMetric(metric, bucket, 60), nil)
}

func (a *ServerController) getXrayMetricsState(c *gin.Context) {
	jsonObj(c, a.xrayMetricsService.State(), nil)
}

func (a *ServerController) getXrayMetricsHistoryBucket(c *gin.Context) {
	metric := c.Param("metric")
	if !slices.Contains(service.XrayMetricKeys, metric) {
		jsonMsg(c, "invalid metric", fmt.Errorf("unknown metric"))
		return
	}
	bucket, ok := parseHistoryBucket(c)
	if !ok {
		return
	}
	jsonObj(c, a.xrayMetricsService.AggregateMetric(metric, bucket, 60), nil)
}

func (a *ServerController) getXrayObservatory(c *gin.Context) {
	jsonObj(c, a.xrayMetricsService.ObservatorySnapshot(), nil)
}

func (a *ServerController) getXrayObservatoryHistoryBucket(c *gin.Context) {
	tag := c.Param("tag")
	if !a.xrayMetricsService.HasObservatoryTag(tag) {
		jsonMsg(c, "invalid tag", fmt.Errorf("unknown observatory tag"))
		return

View on GitHub (pinned to ad32144c42)

Solutions

  1. Use only keys from service.XrayMetricKeys for this endpoint (check the var in your build).
  2. Do not assume system metric names carry over — enumerate the correct list for /history/xray/.
  3. After upgrading Xray-core or the panel, re-check the key set for renames.

Example fix

# before
GET /panel/api/server/history/xray/mem/60   # system key on xray endpoint -> invalid metric

# after
GET /panel/api/server/history/xray/<key from service.XrayMetricKeys>/60
Defensive patterns

Strategy: type-guard

Validate before calling

// keep in sync with service.XrayMetricKeys in the deployed build
const XRAY_METRIC_KEYS = [...] as const // copy from source
function isXrayMetric(m: string): m is (typeof XRAY_METRIC_KEYS)[number] {
  return (XRAY_METRIC_KEYS as readonly string[]).includes(m)
}

Type guard

function isXrayMetric(m: string): m is (typeof XRAY_METRIC_KEYS)[number] {
  return (XRAY_METRIC_KEYS as readonly string[]).includes(m)
}

Prevention

When it happens

Trigger: GET /panel/api/server/history/xray/:metric/:bucket with a system-metric name ('cpu') or an invented Xray counter name instead of one of service.XrayMetricKeys.

Common situations: Confusing the system-metric endpoint's keys with the Xray-metric endpoint's keys; version change renaming Xray counters; scripts reused across endpoint families.

Related errors


AI-assisted analysis of MHSanaei/3x-ui@ad32144c42 (2026-08-15). Data as JSON: /api/errors/a607fa4fc4a57849. Report an issue: GitHub.