bytebase/bytebase · error

unsupported variable %q

Error message

unsupported variable %q

What it means

The CEL equality branch of the access-grant filter compiler only recognizes the variables name, creator, status, query, issue, target, unmask, and export. Any other identifier on the left side of `==` falls through to the default case and returns this error naming the unsupported variable.

Source

Thrown at backend/store/access_grant.go:457

					targetStr, ok := value.(string)
					if !ok {
						return nil, errors.Errorf("target value must be a string")
					}
					return qb.Q().Space("access_grant.payload->'targets' @> jsonb_build_array(to_jsonb(?::text))", targetStr), nil
				case "unmask":
					boolVal, ok := value.(bool)
					if !ok {
						return nil, errors.Errorf("unmask value must be a boolean")
					}
					return qb.Q().Space("COALESCE((access_grant.payload->>'unmask')::boolean, false) = ?", boolVal), nil
				case "export":
					boolVal, ok := value.(bool)
					if !ok {
						return nil, errors.Errorf("export value must be a boolean")
					}
					return qb.Q().Space("COALESCE((access_grant.payload->>'export')::boolean, false) = ?", boolVal), nil
				default:
					return nil, errors.Errorf("unsupported variable %q", variable)
				}
			case celoverloads.Contains:
				call := expr.AsCall()
				target := call.Target()
				if target.Kind() != celast.IdentKind {
					return nil, errors.Errorf("contains target must be an identifier")
				}
				variable := target.AsIdent()
				if variable != "query" {
					return nil, errors.Errorf("contains is not supported on field %q", variable)
				}
				args := call.Args()
				if len(args) != 1 || args[0].Kind() != celast.LiteralKind {
					return nil, errors.Errorf("contains requires a single string literal argument")
				}
				value, ok := args[0].AsLiteral().Value().(string)
				if !ok {
					return nil, errors.Errorf("contains argument must be a string")

View on GitHub (pinned to 1870550677)

Solutions

  1. Use only the supported fields: name, creator, status, query, issue, target, unmask, export.
  2. Fix the field-name typo in the filter.
  3. Check the ListAccessGrantsRequest filter documentation for the allowed fields before adding new ones.
  4. If a new field is genuinely needed, extend the compiler with a new case and SQL predicate.

Example fix

// before
filter := "create_time > \"2024-01-01\""
// after
filter := "status == \"ACTIVE\"" // only documented fields are supported
Defensive patterns

Strategy: validation

Validate before calling

var supportedFields = map[string]bool{
    "name": true, "creator": true, "status": true, "query": true,
    "issue": true, "target": true, "unmask": true, "export": true,
}
// Extract the leading identifier of each clause and check it before sending.
if !supportedFields[field] {
    return fmt.Errorf("field %q is not filterable on access grants", field)
}

Try / catch

if _, err := store.ListAccessGrants(ctx, filter); err != nil {
    if strings.Contains(err.Error(), "unsupported variable") {
        return status.Error(codes.InvalidArgument, err.Error())
    }
    return err
}

Prevention

When it happens

Trigger: ListAccessGrants filter referencing a non-existent or not-filterable field, e.g. `create_time == "..."`, `project == "p"`, or a misspelled field like `statuz == "ACTIVE"`.

Common situations: Typos in hand-written filters, copying filter strings from other resources (issues, audit logs) that support different fields, and clients assuming all proto fields are filterable.

Understand the failure class

Background: "Invalid query parameter" / "Failed to parse value of ...": fixing bad query string parameters across APIs — this error's family across 36 libraries.

Related errors


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