{"record":{"id":"add6d481d09912e3","repo":"bytebase/bytebase","slug":"unexpected-status-code-d-s","errorCode":null,"errorMessage":"unexpected status code %d: %s","messagePattern":"unexpected status code (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/plugin/db/elasticsearch/sync.go","lineNumber":93,"sourceCode":"\t\t\treturn \"\", err\n\t\t}\n\t\treturn info.Version.Number, nil\n\t}\n\tresp, err := d.basicAuthClient.Do(\"GET\", []byte(\"/\"), nil)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer resp.Body.Close()\n\n\tbytes, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn \"\", errors.Wrap(err, \"failed to read response body\")\n\t}\n\n\t// Check HTTP status code\n\tif resp.StatusCode != http.StatusOK {\n\t\t// Include response body for debugging\n\t\treturn \"\", errors.Errorf(\"unexpected status code %d: %s\", resp.StatusCode, string(bytes))\n\t}\n\n\tvar result VersionResult\n\terr = json.Unmarshal(bytes, &result)\n\tif err != nil {\n\t\t// Include response body to help debug parsing issues\n\t\tbodyPreview, truncated := common.TruncateString(string(bytes), 500)\n\t\tif truncated {\n\t\t\tbodyPreview += \"...\"\n\t\t}\n\t\treturn \"\", errors.Wrapf(err, \"failed to parse version response: %s\", bodyPreview)\n\t}\n\n\treturn result.Version.Number, nil\n}\n\ntype IndicesResult struct {\n\tIndexSize string `json:\"store.size\"`","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/bytebase/bytebase/blob/1870550677fe08f0d2a78c07acd27541464eb945/backend/plugin/db/elasticsearch/sync.go#L75-L111","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: root endpoint blocked, GET / returns 403\n// xpack: security.rest.roles: deny /\n// after: allow authenticated read of the root endpoint\nGET / -> 200 {\"version\":{\"number\":\"8.11.0\",...}}","handlingStrategy":"validation","validationCode":"// Require exactly 200 from the root endpoint before syncing\nresp, err := http.Get(\"http://es.internal:9200/\")\nif err != nil || resp.StatusCode != http.StatusOK {\n\treturn fmt.Errorf(\"GET / must return 200 JSON (got status or network error)\")\n}","typeGuard":null,"tryCatchPattern":"if err != nil {\n\tif strings.Contains(err.Error(), \"unexpected status code\") {\n\t\t// branch on embedded status: 401 credentials, 403 grants, 404 URL\n\t}\n\treturn err\n}","preventionTips":["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"],"tags":["http","elasticsearch","sync","status-code","version"],"backgroundTag":"http-non-200-response","analyzedSha":"1870550677fe08f0d2a78c07acd27541464eb945","analyzedAt":"2026-09-06T21:16:13.665Z","contentChangedAt":"2026-09-06T21:16:13.665Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}