MHSanaei/3x-ui · error
invalid tag (unknown observatory tag)
Error message
invalid tag (unknown observatory tag)
What it means
ServerController.getXrayObservatoryHistoryBucket validates c.Param("tag") via xrayMetricsService.HasObservatoryTag — only tags actually registered from Xray's burst-observatory outbound config are accepted. 'invalid tag' (detail 'unknown observatory tag') means the tag is not among the observed outbound tags, either mistyped or the observatory feature not configured/started.
Source
Thrown at internal/web/controller/server.go:174
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
}
bucket, ok := parseHistoryBucket(c)
if !ok {
return
}
jsonObj(c, a.xrayMetricsService.AggregateObservatory(tag, bucket, 60), nil)
}
func (a *ServerController) getXrayVersion(c *gin.Context) {
versions, err := a.serverService.GetXrayVersionsCached()
if err != nil {
jsonMsg(c, I18nWeb(c, "getVersion"), err)
return
}
jsonObj(c, versions, nil)
}
View on GitHub (pinned to ad32144c42)
Solutions
- First fetch GET /panel/api/server/xrayObservatory (ObservatorySnapshot) and use a tag that appears there.
- Align the tag with the outbound's tag field in your Xray config exactly (case-sensitive).
- If the snapshot is empty, enable/configure the observatory in the panel and restart Xray so tags register.
Example fix
# before GET /panel/api/server/history/observatory/proxy-1/60 # invalid tag # after curl /panel/api/server/xrayObservatory # see real tags, e.g. "proxy1" GET /panel/api/server/history/observatory/proxy1/60
Defensive patterns
Strategy: validation
Validate before calling
const snap = await fetch('/panel/api/server/xrayObservatory').then(r => r.json())
const validTags = new Set(Object.keys(snap?.success?.tags ?? snap?.obj?.tags ?? {}))
if (!validTags.has(tag)) throw new Error(`unknown observatory tag ${tag}`) Prevention
- Always enumerate live tags via the observatory snapshot before requesting history.
- Keep outbound tags stable and case-sensitive-identical across config and dashboards.
- Treat an empty snapshot as 'observatory not configured' rather than 'bad tag'.
When it happens
Trigger: GET /panel/api/server/history/observatory/:tag/:bucket with a tag that does not match any outbound tag under the observatory config — e.g. 'proxy-1' when the outbound tag is 'proxy1', or any tag when the panel runs no burst observatory.
Common situations: Outbound tag renamed in config without updating dashboards; observatory disabled or Xray not running so no tags are registered; a fresh panel before any observatory data arrives.
Related errors
AI-assisted analysis of MHSanaei/3x-ui@ad32144c42 (2026-08-15).
Data as JSON: /api/errors/d9896fcd234156ac.
Report an issue: GitHub.