{"record":{"id":"da1357f2169703a1","repo":"thanos-io/thanos","slug":"action-cannot-be-empty","errorCode":null,"errorMessage":"Action cannot be empty","messagePattern":"Action cannot be empty","errorType":"http","errorClass":"ApiError","httpStatus":400,"severity":"error","filePath":"pkg/api/blocks/v1.go","lineNumber":109,"sourceCode":"\n\tr.Get(\"/blocks\", instr(\"blocks\", bapi.blocks))\n\tr.Post(\"/blocks/mark\", instr(\"blocks_mark\", bapi.markBlock))\n}\n\nfunc (bapi *BlocksAPI) markBlock(r *http.Request) (any, []error, *api.ApiError, func()) {\n\tif bapi.disableAdminOperations {\n\t\treturn nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: errors.New(\"Admin operations are disabled\")}, func() {}\n\t}\n\tidParam := r.FormValue(\"id\")\n\tactionParam := r.FormValue(\"action\")\n\tdetailParam := r.FormValue(\"detail\")\n\n\tif idParam == \"\" {\n\t\treturn nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: errors.New(\"ID cannot be empty\")}, func() {}\n\t}\n\n\tif actionParam == \"\" {\n\t\treturn nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: errors.New(\"Action cannot be empty\")}, func() {}\n\t}\n\n\tid, err := ulid.Parse(idParam)\n\tif err != nil {\n\t\treturn nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: errors.Errorf(\"ULID %q is not valid: %v\", idParam, err)}, func() {}\n\t}\n\n\tactionType := parse(actionParam)\n\tswitch actionType {\n\tcase Deletion:\n\t\terr := block.MarkForDeletion(r.Context(), bapi.logger, bapi.bkt, id, detailParam, promauto.With(nil).NewCounter(prometheus.CounterOpts{}))\n\t\tif err != nil {\n\t\t\treturn nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}, func() {}\n\t\t}\n\tcase NoCompaction:\n\t\terr := block.MarkForNoCompact(r.Context(), bapi.logger, bapi.bkt, id, metadata.ManualNoCompactReason, detailParam, promauto.With(nil).NewCounter(prometheus.CounterOpts{}))\n\t\tif err != nil {\n\t\t\treturn nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}, func() {}","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/thanos-io/thanos/blob/35b8b991177def87ed52dcf10f9b6d87f07282c8/pkg/api/blocks/v1.go#L91-L127","documentation":"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'.","triggerScenarios":"POST /api/v1/blocks/mark with id set but no action form field (or action= empty).","commonSituations":"Automation supplying only the block id; refactored scripts dropping the action parameter; interactive calls assuming a default action exists.","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."],"exampleFix":"// before\ncurl -X POST http://thanos:9090/api/v1/blocks/mark -d 'id=01ARZ3NDEKTSV4RRFFQ69G5FAV'\n// after\ncurl -X POST http://thanos:9090/api/v1/blocks/mark -d 'id=01ARZ3NDEKTSV4RRFFQ69G5FAV' -d 'action=deletion' -d 'detail=marked by cleanup job'","handlingStrategy":"validation","validationCode":"var validActions = map[string]bool{\"deletion\": true, \"no-compact\": true}\nif !validActions[action] {\n    return fmt.Errorf(\"action %q must be one of deletion|no-compact\", action)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["http","api","validation"],"backgroundTag":"missing-required-argument","analyzedSha":"35b8b991177def87ed52dcf10f9b6d87f07282c8","analyzedAt":"2026-09-07T01:49:59.689Z","contentChangedAt":"2026-09-07T01:49:59.689Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}