vitessio/vitess · error

not allowed: read-only security-policy enforced

Error message

not allowed: read-only security-policy enforced

What it means

When fetching table sizes per shard, vtadmin selects one random serving tablet from each shard to query. If a shard has no tablets in the SERVING state, the query cannot proceed and this wrapped ErrNoServingTablet error is returned for that shard.

Source

Thrown at go/acl/read_only_policy.go:24

You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package acl

import (
	"errors"
	"net/http"
)

var errReadOnly = errors.New("not allowed: read-only security-policy enforced")

// readOnlyPolicy allows DEBUGGING and MONITORING roles for everyone,
// while denying any other roles (e.g. ADMIN) for everyone.
type readOnlyPolicy struct{}

// CheckAccessHTTP disallows all HTTP access.
func (readOnlyPolicy) CheckAccessHTTP(req *http.Request, role string) error {
	switch role {
	case DEBUGGING, MONITORING:
		return nil
	default:
		return errReadOnly
	}
}

func init() {
	RegisterPolicy("read-only", readOnlyPolicy{})
}

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Start or restore at least one serving tablet for the affected shard (vtctldclient StartTablet / restart vttablet)
  2. Check tablet states with vtctldclient GetTablets and fix any tablets stuck non-serving
  3. Prune truly dead shards/tablets from the topology if the shard is intentionally retired
Defensive patterns

Strategy: validation

Validate before calling

serving := 0
for _, t := range tablets {
	if t.Tablet.Keyspace == ks && t.Tablet.Shard == shard && t.State == vtadminpb.Tablet_SERVING {
		serving++
	}
}
if serving == 0 { return errors.New("shard has no serving tablets; skip or fix before calling") }

Type guard

func hasServingTablet(tablets []*vtadminpb.Tablet, ks, shard string) bool {
	for _, t := range tablets {
		if t.Tablet.Keyspace == ks && t.Tablet.Shard == shard && t.State == vtadminpb.Tablet_SERVING {
			return true
		}
	}
	return false
}

Prevention

When it happens

Trigger: Calling a table-size / schema RPC that iterates shards when a shard in the keyspace has zero tablets with State == Tablet_SERVING (all replicas drained, only non-serving tablets present).

Common situations: A shard whose tablets are all down for maintenance; a newly created shard before tablets are started; tablets stuck in a non-serving state after a failed restart; wrong cluster selected in vtadmin config.

Related errors


AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01). Data as JSON: /api/errors/460a9cba11304d72. Report an issue: GitHub.