bytebase/bytebase · error

rule %s requires naming payload

Error message

rule %s requires naming payload

What it means

Naming rules with regex validation (NAMING_TABLE, NAMING_COLUMN, NAMING_COLUMN_AUTO_INCREMENT) carry their configuration in a NamingRulePayload. validateSQLReviewRule rejects such a rule when GetNamingPayload() returns nil, meaning the payload was never attached to the rule.

Source

Thrown at backend/api/v1/review_config_service.go:351

			return errors.Errorf("invalid rule engine: ENGINE_UNSPECIFIED is not allowed for rule %q", rule.Type)
		}
		if err := validateSQLReviewRule(rule); err != nil {
			return err
		}
	}
	return nil
}

// validateSQLReviewRule validates a single SQL review rule's payload.
func validateSQLReviewRule(rule *v1pb.SQLReviewRule) error {
	ruleType := storepb.SQLReviewRule_Type(rule.Type)

	switch ruleType {
	// Naming rules with regex validation
	case storepb.SQLReviewRule_NAMING_TABLE, storepb.SQLReviewRule_NAMING_COLUMN, storepb.SQLReviewRule_NAMING_COLUMN_AUTO_INCREMENT:
		payload := rule.GetNamingPayload()
		if payload == nil {
			return errors.Errorf("rule %s requires naming payload", ruleType)
		}
		// At least one of format or maxLength must be set
		if payload.Format == "" && payload.MaxLength <= 0 {
			return errors.Errorf("naming rule must specify either format or max_length for rule %s", ruleType)
		}
		// If format is set, validate it compiles
		if payload.Format != "" {
			if _, err := regexp.Compile(payload.Format); err != nil {
				return errors.Wrapf(err, "invalid naming rule format pattern %q for rule %s", payload.Format, ruleType)
			}
		}
		// If maxLength is set, validate it's positive (maxLength == 0 means not set)
		if payload.MaxLength < 0 {
			return errors.Errorf("naming rule max_length cannot be negative for rule %s, got %d", ruleType, payload.MaxLength)
		}

	// Naming rules with template token validation
	case storepb.SQLReviewRule_NAMING_INDEX_FK, storepb.SQLReviewRule_NAMING_INDEX_IDX, storepb.SQLReviewRule_NAMING_INDEX_UK, storepb.SQLReviewRule_NAMING_INDEX_PK, storepb.SQLReviewRule_TABLE_DROP_NAMING_CONVENTION:

View on GitHub (pinned to 1870550677)

Solutions

  1. Attach a NamingRulePayload (with format and/or maxLength) to the rule's payload oneof
  2. Omit the rule entirely until its payload is configured
  3. Verify the JSON/proto payload field name matches the oneof case (namingPayload)

Example fix

// before
{type: "NAMING_TABLE", level: "ERROR", engine: "ENGINE_MYSQL"}
// after
{type: "NAMING_TABLE", level: "ERROR", engine: "ENGINE_MYSQL", namingPayload: {format: "^t_[a-z]+$"}}
Defensive patterns

Strategy: validation

Validate before calling

if isRegexNamingRule(rule.Type) && rule.GetNamingPayload() == nil {
  return fmt.Errorf("rule %s needs a namingPayload before saving", rule.Type)
}

Type guard

func hasNamingPayload(r *v1pb.SQLReviewRule) bool { return r.GetNamingPayload() != nil }

Prevention

When it happens

Trigger: Creating or updating a review config with one of the three regex naming rules but no payload field set (oneof payload left empty in the request).

Common situations: API consumers that set rule type/level/engine but forget the payload oneof; UIs that create the rule shell before the payload form is filled; migrations copying rules between configs and dropping the payload.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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