thanos-io/thanos · error · ApiError
Action cannot be empty
Error message
Action cannot be empty
What it means
markBlock requires the form parameter 'action' stating what to mark the block for (e.g. deletion, no-compact). A request with a valid id but missing/empty action is rejected with ErrorBadData 'Action cannot be empty'.
Solutions
- Include the action form field with a supported value, e.g. action=deletion (or no-compact) along with id and detail.
- Check the markBlock handler's valid actions list and pass exactly one.
- Validate the action client-side before calling the endpoint.
Example fix
// before curl -X POST http://thanos:9090/api/v1/blocks/mark -d 'id=01ARZ3NDEKTSV4RRFFQ69G5FAV' // after curl -X POST http://thanos:9090/api/v1/blocks/mark -d 'id=01ARZ3NDEKTSV4RRFFQ69G5FAV' -d 'action=deletion' -d 'detail=marked by cleanup job'
Defensive patterns
Strategy: validation
Validate before calling
var validActions = map[string]bool{"deletion": true, "no-compact": true}
if !validActions[action] {
return fmt.Errorf("action %q must be one of deletion|no-compact", action)
} Prevention
- Define the allowed action constants once and share them across automation
- Always pass detail alongside action for auditability
- Validate form params in the automation layer before hitting the endpoint
When it happens
Trigger: POST /api/v1/blocks/mark with id set but no action form field (or action= empty).
Common situations: Automation supplying only the block id; refactored scripts dropping the action parameter; interactive calls assuming a default action exists.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- ID cannot be empty
- invalid targets parameter state=
- invalid rules parameter type=
- failed to get prometheus version
- invalid parameter ;
AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07).
Data as JSON: /api/errors/da1357f2169703a1.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/api/blocks/v1.go:109
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() {}
}
actionType := parse(actionParam)
switch actionType {
case Deletion:
err := block.MarkForDeletion(r.Context(), bapi.logger, bapi.bkt, id, detailParam, promauto.With(nil).NewCounter(prometheus.CounterOpts{}))
if err != nil {
return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}, func() {}
}
case NoCompaction:
err := block.MarkForNoCompact(r.Context(), bapi.logger, bapi.bkt, id, metadata.ManualNoCompactReason, detailParam, promauto.With(nil).NewCounter(prometheus.CounterOpts{}))
if err != nil {
return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}, func() {}View on GitHub (pinned to 35b8b99117)