bytebase/bytebase · error

invalid label value %q for key %q: must contain only letters

Error message

invalid label value %q for key %q: must contain only letters, numbers, underscores, and dashes (max 63 chars)

What it means

validateLabels rejects label values not matching ^[a-zA-Z0-9_-]{0,63}$: values may contain letters (any case), digits, underscores, and dashes, up to 63 chars, and may be empty. The error names both the offending value and its key.

Source

Thrown at backend/api/v1/common.go:67

// - Maximum 64 labels allowed
// - Keys must start with lowercase letter, then contain only lowercase letters, numbers, underscores, and dashes (max 63 chars)
// - Values can contain letters, numbers, underscores, and dashes (max 63 chars, can be empty)
func validateLabels(labels map[string]string) error {
	if len(labels) > 64 {
		return errors.Errorf("maximum 64 labels allowed, got %d", len(labels))
	}
	// Key pattern: must start with lowercase letter, then lowercase letters, numbers, underscores, dashes (max 63 chars)
	keyPattern := `^[a-z][a-z0-9_-]{0,62}$`
	// Value pattern: letters, numbers, underscores, dashes (max 63 chars, can be empty)
	valuePattern := `^[a-zA-Z0-9_-]{0,63}$`
	keyRegex := regexp.MustCompile(keyPattern)
	valueRegex := regexp.MustCompile(valuePattern)
	for key, value := range labels {
		if !keyRegex.MatchString(key) {
			return errors.Errorf("invalid label key %q: must start with lowercase letter and contain only lowercase letters, numbers, underscores, and dashes (max 63 chars)", key)
		}
		if !valueRegex.MatchString(value) {
			return errors.Errorf("invalid label value %q for key %q: must contain only letters, numbers, underscores, and dashes (max 63 chars)", value, key)
		}
	}
	return nil
}

type Expression struct {
	Key      string
	Operator OperatorType
	Value    string
}

// ParseFilter will parse the simple filter.
// TODO(rebelice): support more complex filter.
// Currently we support the following syntax:
//  1. for single expression:
//     i.   defined as `key comparator "val"`.
//     ii.  Comparator can be `=`, `!=`, `>`, `>=`, `<`, `<=`.
//     iii. If val doesn't contain space, we can omit the double quotes.

View on GitHub (pinned to 1870550677)

Solutions

  1. Replace invalid characters (spaces, slashes, dots) with dashes or underscores
  2. Truncate values to 63 characters
  3. Slugify values before assigning them to labels
  4. Pre-validate values with the same regex on the client

Example fix

// before
labels := map[string]string{"env": "production / eu-west"}
// after
labels := map[string]string{"env": "production-eu-west"}
Defensive patterns

Strategy: validation

Validate before calling

var valRe = regexp.MustCompile(`^[a-zA-Z0-9_-]{0,63}$`)
func validLabelValue(v string) bool { return valRe.MatchString(v) }

Try / catch

err := client.UpdateProject(ctx, req)
if err != nil && strings.Contains(err.Error(), "invalid label value") {
	// slugify/truncate values and retry
}

Prevention

When it happens

Trigger: CreateInstance/UpdateInstance/CreateProject/UpdateProject with a label value containing spaces, dots, slashes, colons, unicode, or longer than 63 characters.

Common situations: Values copied from URLs or file paths ('prod/eu-west'); emails as values; human-readable values with spaces; team names longer than 63 chars.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of bytebase/bytebase@1870550677 (2026-09-06). Data as JSON: /api/errors/5e748eb1a642d08a. Report an issue: GitHub.