bytebase/bytebase · error
status value must be a string
Error message
status value must be a string
What it means
The access-grant CEL filter compiler in backend/store/access_grant.go converts a CEL filter expression into SQL. When it encounters `status == <value>` and the CEL literal is not a Go string, it refuses to build the predicate and returns this error. It guards the typed conversion before the value reaches getAccessGrantStatusFilter.
Source
Thrown at backend/store/access_grant.go:400
_, accessGrantID, err := common.GetProjectIDAccessGrantID(nameStr)
if err != nil {
return nil, errors.Wrapf(err, "invalid access grant name %q", nameStr)
}
return qb.Q().Space("access_grant.id = ?", accessGrantID), nil
case "creator":
creatorStr, ok := value.(string)
if !ok {
return nil, errors.Errorf("creator value must be a string")
}
if !strings.HasPrefix(creatorStr, "users/") {
return nil, errors.Errorf("creator must have format \"users/{email}\", got %q", creatorStr)
}
creatorEmail := strings.TrimPrefix(creatorStr, "users/")
return qb.Q().Space("access_grant.creator = ?", creatorEmail), nil
case "status":
statusStr, ok := value.(string)
if !ok {
return nil, errors.Errorf("status value must be a string")
}
return getAccessGrantStatusFilter(statusStr)
case "query":
queryStr, ok := value.(string)
if !ok {
return nil, errors.Errorf("query value must be a string")
}
// Trim the same whitespace set on both sides (boundary
// only) so the run-time JIT match in preCheckAccess
// survives invisible boundary differences — most
// commonly a trailing \n that Monaco's getValue() emits
// in the request drawer but that the editor's
// getActiveStatement() doesn't.
//
// We deliberately do NOT collapse internal whitespace.
// Doing so would let "SELECT * FROM t --\nWHERE x=1"
// compare equal to "SELECT * FROM t -- WHERE x=1",
// silently authorizing a query with the WHERE clauseView on GitHub (pinned to 1870550677)
Solutions
- Quote the status value in the filter: `status == "ACTIVE"`.
- Use the exact string constant accepted by getAccessGrantStatusFilter (e.g. STATE_ACTIVE / STATE_DISABLED per the proto enum names).
- Fix the client/SDK that is serializing the enum as a number into the filter string.
- If the value type is legitimately variable, add an explicit string cast or a numeric branch in the compiler before the type assertion.
Example fix
// before filter = "status == 1" // after filter = "status == \"ACTIVE\""
Defensive patterns
Strategy: validation
Validate before calling
// Before sending the filter, ensure the status literal is a quoted string:
if !strings.Contains(filter, `status == "`) && strings.Contains(filter, "status ==") {
return fmt.Errorf("filter %q: status literal must be a quoted string", filter)
} Type guard
func isStringLiteral(v any) (string, bool) {
s, ok := v.(string)
return s, ok
} Try / catch
qq, err := store.ListAccessGrants(ctx, filter)
if err != nil {
if strings.Contains(err.Error(), "status value must be a string") {
// fall back to a corrected/quoted filter or surface a 400 to the client
}
return err
} Prevention
- Always quote CEL string literals; never compare enums as numbers
- Keep filter strings next to proto enum definitions and derive names from the enum
- Add a unit test per filter field asserting literal types
- Validate filters with common.ParseCELFilter in a dry run before issuing list calls
When it happens
Trigger: Calling ListAccessGrants (or SearchAccessGrants) with a filter like `status == 1`, `status == true`, or `status in [1]`-style comparisons where the compared value is a number, bool, list, or bytes literal instead of a string.
Common situations: Hand-written CEL filters with unquoted enum values (`status == ACTIVE` resolves to an identifier, or `status == 0`), SDK clients passing numeric status codes from older API versions, and code generators that emit the wire enum number rather than the string state name.
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
- query value must be a string
- CodeInvalidArgument
- category value must be a string, got %T
- issue value must be a string
- target value must be a string
AI-assisted analysis of bytebase/bytebase@1870550677 (2026-09-06).
Data as JSON: /api/errors/af665ca48e418cf2.
Report an issue: GitHub.