bytebase/bytebase · error

category value must be a string, got %T

Error message

category value must be a string, got %T

What it means

extractCategoryFromExpr requires the value compared against 'category' to be a CEL string literal. When the AST contains category == <something else> (int, bool, list, bytes), it throws this typed error including the Go type of the offending value.

Source

Thrown at backend/api/v1/release_service.go:495

	return category, nil
}

// extractCategoryFromExpr walks the CEL AST to extract the category value.
func extractCategoryFromExpr(expr celast.Expr) (string, error) {
	switch expr.Kind() {
	case celast.CallKind:
		call := expr.AsCall()
		functionName := call.FunctionName()

		// Handle: category == "value"
		if functionName == celoperators.Equals {
			variable, value := getVariableAndValueFromExpr(expr)
			if variable == "category" {
				if categoryValue, ok := value.(string); ok {
					return categoryValue, nil
				}
				return "", errors.Errorf("category value must be a string, got %T", value)
			}
			return "", errors.Errorf("unsupported filter variable: %s", variable)
		}

		return "", errors.Errorf("unsupported operator: %s (only '==' is supported)", functionName)

	default:
		return "", errors.Errorf("unsupported expression type")
	}
}

func renderTrain(template, timezone string, t time.Time) (string, error) {
	// Validate template
	if err := validateTemplate(template); err != nil {
		return "", err
	}

	// Validate timezone

View on GitHub (pinned to 1870550677)

Solutions

  1. Quote the category value in the filter so it is a CEL string: category == "my-category".
  2. Confirm the exact category name via ListReleaseCategories and use that string verbatim.
  3. If a non-string category identifier is genuinely needed, extend the parser or the API contract.

Example fix

// before
filter = "category == 42"
// after
filter = "category == \"42\""
Defensive patterns

Strategy: validation

Validate before calling

const m = filter.match(/^category\s*==\s*(.+)$/);
if (!m || !/^"[^"]*"$/.test(m[1].trim())) throw new Error('category value must be a quoted string');

Try / catch

try {
  const resp = await client.listReleases({ filter });
} catch (err) {
  if (err.message?.includes('must be a string')) {
    filter = `category == "${String(rawCategoryValue)}"`;
  }
}

Prevention

When it happens

Trigger: ListReleases with filter like category == 123, category == true, or category == ["a"]. The variable is recognized but the value fails the string type assertion.

Common situations: Generated clients passing numeric category IDs; accidental unquoted literal in the filter string; confusion between a category name (string) and an internal numeric ID.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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