thanos-io/thanos · warning · ApiError
Admin operations are disabled
Error message
Admin operations are disabled
What it means
The Blocks API's markBlock endpoint (POST /blocks/mark) refuses to run when the API was started with admin operations disabled (--admin.disable). Block mark/delete operations are guarded by this flag as a safety measure.
Solutions
- Restart the Thanos component without the --admin.disable flag if admin operations are intended.
- Perform block marking via the object store tooling (thanos tools bucket mark) instead of the API.
- Point the automation at an instance that has admin operations enabled.
Example fix
// before thanos sidecar --prometheus.url=http://localhost:9090 --admin.disable // after thanos sidecar --prometheus.url=http://localhost:9090 # admin ops enabled (or use `thanos tools bucket mark`)
Defensive patterns
Strategy: validation
Validate before calling
// probe admin availability first
resp, _ := http.Post(baseURL+"/api/v1/blocks/mark", "application/x-www-form-urlencoded", strings.NewReader("id=test&action=deletion"))
if resp != nil && resp.StatusCode == 400 { /* admin likely disabled; use bucket tooling */ } Try / catch
resp, err := http.PostForm(url, vals)
if err != nil { return err }
var e struct{ Error string `json:"error"`; Status string `json:"status"` }
json.NewDecoder(resp.Body).Decode(&e)
if e.Status == "error" && strings.Contains(e.Error, "Admin operations are disabled") {
return fmt.Errorf("admin ops disabled on this instance; use `thanos tools bucket mark` instead")
} Prevention
- Know which Thanos instances run with --admin.disable before automating mark calls
- Use `thanos tools bucket mark` for block marking against read-only deployments
- Keep a dedicated admin-enabled endpoint for automation
When it happens
Trigger: POST /api/v1/blocks/mark while the blocks API server was constructed with disableAdminOperations=true (Thanos started with --admin.disable).
Common situations: Production deployments launched with --admin.disable attempting block metadata marking via API; automation tooling calling mark endpoints against a read-only store gateway/UI instance.
Related errors
- retention failed
- failed to get prometheus version
- error marshaling response
- ID cannot be empty
- Action cannot be empty
AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07).
Data as JSON: /api/errors/28917149406e90e3.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/api/blocks/v1.go:98
},
disableCORS: disableCORS,
bkt: bkt,
disableAdminOperations: disableAdminOperations,
}
}
func (bapi *BlocksAPI) Register(r *route.Router, tracer opentracing.Tracer, logger log.Logger, ins extpromhttp.InstrumentationMiddleware, logMiddleware *logging.HTTPServerMiddleware) {
bapi.baseAPI.Register(r, tracer, logger, ins, logMiddleware)
instr := api.GetInstr(tracer, logger, ins, logMiddleware, bapi.disableCORS)
r.Get("/blocks", instr("blocks", bapi.blocks))
r.Post("/blocks/mark", instr("blocks_mark", bapi.markBlock))
}
func (bapi *BlocksAPI) markBlock(r *http.Request) (any, []error, *api.ApiError, func()) {
if bapi.disableAdminOperations {
return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: errors.New("Admin operations are disabled")}, func() {}
}
idParam := r.FormValue("id")
actionParam := r.FormValue("action")
detailParam := r.FormValue("detail")
if idParam == "" {
return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: errors.New("ID cannot be empty")}, func() {}
}
if actionParam == "" {
return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: errors.New("Action cannot be empty")}, func() {}
}
id, err := ulid.Parse(idParam)
if err != nil {
return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: errors.Errorf("ULID %q is not valid: %v", idParam, err)}, func() {}
}
View on GitHub (pinned to 35b8b99117)