thanos-io/thanos · error

parse Prometheus config

Error message

parse Prometheus config: %v

What it means

After decoding the config JSON, ExternalLabels parses the embedded Prometheus configuration YAML to extract global.external_labels. This error wraps yaml.Unmarshal failures, embedding the raw YAML text so the malformed config can be inspected.

Solutions

  1. Inspect the YAML included in the error message for syntax problems
  2. Validate the Prometheus config with promtool check config
  3. Ensure external_labels values are plain strings in prometheus.yml
  4. Simplify generated config (avoid exotic YAML anchors) and reload Prometheus

Example fix

// before (prometheus.yml)
global:
  external_labels:
    cluster: &anchor {name: prod}   # map where string expected
// after
global:
  external_labels:
    cluster: prod
    name: prod
Defensive patterns

Strategy: validation

Validate before calling

func externalLabelsAreStrings(cfgYAML string) error {
    var probe struct {
        Global struct {
            ExternalLabels map[string]string `yaml:"external_labels"`
        } `yaml:"global"`
    }
    return yaml.Unmarshal([]byte(cfgYAML), &probe)
}

Try / catch

labels, err := client.ExternalLabels(ctx, baseURL)
if err != nil {
    if strings.Contains(err.Error(), "parse Prometheus config") {
        log.Printf("prometheus config YAML invalid: %v", err)
    }
    return err
}

Prevention

When it happens

Trigger: The YAML string inside data.yaml of the /api/v1/status/config response cannot be unmarshaled into the expected {global: {external_labels: map[string]string}} structure — e.g. YAML with anchors/templating the parser rejects, or non-string external label values.

Common situations: Prometheus config generated with unsupported YAML features (anchors producing exotic types); external_labels values that are not strings; corrupted config served by a proxy cache; third-party Prometheus forks emitting a different config format.

Related errors


AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07). Data as JSON: /api/errors/a9f8ad5599a48fe7. Report an issue: GitHub.

Appendix: source

Thrown at pkg/promclient/promclient.go:209

	body, _, err := c.req2xx(ctx, &u, http.MethodGet, nil)
	if err != nil {
		return labels.EmptyLabels(), err
	}
	var d struct {
		Data struct {
			YAML string `json:"yaml"`
		} `json:"data"`
	}
	if err := json.Unmarshal(body, &d); err != nil {
		return labels.EmptyLabels(), errors.Wrapf(err, "unmarshal response: %v", string(body))
	}
	var cfg struct {
		GlobalConfig struct {
			ExternalLabels map[string]string `yaml:"external_labels"`
		} `yaml:"global"`
	}
	if err := yaml.Unmarshal([]byte(d.Data.YAML), &cfg); err != nil {
		return labels.EmptyLabels(), errors.Wrapf(err, "parse Prometheus config: %v", d.Data.YAML)
	}

	return labels.FromMap(cfg.GlobalConfig.ExternalLabels), nil
}

type Flags struct {
	TSDBPath           string         `json:"storage.tsdb.path"`
	TSDBRetention      model.Duration `json:"storage.tsdb.retention"`
	TSDBMinTime        model.Duration `json:"storage.tsdb.min-block-duration"`
	TSDBMaxTime        model.Duration `json:"storage.tsdb.max-block-duration"`
	TSDBDelayCompact   string         `json:"storage.tsdb.delay-compact-file.path"`
	WebEnableAdminAPI  bool           `json:"web.enable-admin-api"`
	WebEnableLifecycle bool           `json:"web.enable-lifecycle"`
}

// UnmarshalJSON implements the json.Unmarshaler interface.
func (f *Flags) UnmarshalJSON(b []byte) error {
	// TODO(bwplotka): Avoid this custom unmarshal by:

View on GitHub (pinned to 35b8b99117)