bytebase/bytebase · error
unexpected status code %d: %s
Error message
unexpected status code %d: %s
What it means
Thrown by getVersion() when the root endpoint GET / returns any status other than 200. Unlike the query path, this requires exactly 200, so even 2xx variants like 204 fail. The full response body is embedded in the message to expose the underlying cluster or proxy error. Wrapped by 2556 in SyncInstance.
Source
Thrown at backend/plugin/db/elasticsearch/sync.go:93
return "", err
}
return info.Version.Number, nil
}
resp, err := d.basicAuthClient.Do("GET", []byte("/"), nil)
if err != nil {
return "", err
}
defer resp.Body.Close()
bytes, err := io.ReadAll(resp.Body)
if err != nil {
return "", errors.Wrap(err, "failed to read response body")
}
// Check HTTP status code
if resp.StatusCode != http.StatusOK {
// Include response body for debugging
return "", errors.Errorf("unexpected status code %d: %s", resp.StatusCode, string(bytes))
}
var result VersionResult
err = json.Unmarshal(bytes, &result)
if err != nil {
// Include response body to help debug parsing issues
bodyPreview, truncated := common.TruncateString(string(bytes), 500)
if truncated {
bodyPreview += "..."
}
return "", errors.Wrapf(err, "failed to parse version response: %s", bodyPreview)
}
return result.Version.Number, nil
}
type IndicesResult struct {
IndexSize string `json:"store.size"`View on GitHub (pinned to 1870550677)
Solutions
- Read the embedded status and body — it identifies auth (401), permission (403), routing (404), or upstream (502/503) failure.
- If 401: correct the username/password (or API key) in the datasource configuration.
- If 404: verify the URL and any path prefix; GET / must hit the cluster root exactly.
- If 403: grant the sync user access to the root endpoint (cluster 'monitor' privilege) or unblock GET / in the proxy/security rules.
- Confirm independently with curl -i http://host:9200/ — it must return HTTP 200 with a JSON version object before Bytebase can sync.
Example fix
// before: root endpoint blocked, GET / returns 403
// xpack: security.rest.roles: deny /
// after: allow authenticated read of the root endpoint
GET / -> 200 {"version":{"number":"8.11.0",...}} Defensive patterns
Strategy: validation
Validate before calling
// Require exactly 200 from the root endpoint before syncing
resp, err := http.Get("http://es.internal:9200/")
if err != nil || resp.StatusCode != http.StatusOK {
return fmt.Errorf("GET / must return 200 JSON (got status or network error)")
} Try / catch
if err != nil {
if strings.Contains(err.Error(), "unexpected status code") {
// branch on embedded status: 401 credentials, 403 grants, 404 URL
}
return err
} Prevention
- curl -i http://host:9200/ must show 200 before saving the datasource
- Double-check any URL path prefix on proxied clusters
- Grant cluster 'monitor' so the root endpoint is accessible to the sync user
When it happens
Trigger: Instance sync where GET / returns 401 (bad/missing credentials), 403 (root path denied), 404 (wrong URL path/prefix), 502/503 (proxy upstream failure), or any redirect followed to an error page.
Common situations: Missing or wrong datasource credentials; ES behind a proxy that restricts GET /; datasource URL including a wrong base path (e.g. /elasticsearch prefix mismatch); cluster in a failed state answering via LB error pages; security plugin blocking root endpoint for the sync user.
Related errors
- failed to fetch version from Elasticsearch server
- failed to read response body
- request failed with status code %d: %s
- received HTML error response (status %d): %s
- failed to parse json body
AI-assisted analysis of bytebase/bytebase@1870550677 (2026-09-06).
Data as JSON: /api/errors/add6d481d09912e3.
Report an issue: GitHub.