bytebase/bytebase · error

export value must be a boolean

Error message

export value must be a boolean

What it means

For `export == <value>` the compiler asserts a Go bool literal, producing the predicate COALESCE((payload->>'export')::boolean, false) = ?. Non-bool literals (strings, numbers) are rejected with this error.

Source

Thrown at backend/store/access_grant.go:453

						return nil, errors.Wrapf(err, "invalid issue name %q", issueStr)
					}
					return qb.Q().Space("(access_grant.payload->>'issueId')::bigint = ?", issueUID), nil
				case "target":
					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")

View on GitHub (pinned to 1870550677)

Solutions

  1. Write the filter with bare booleans: `export == true` / `export == false`.
  2. Fix the value source so booleans stay typed (JSON bool, Go bool) rather than "true"/"false" strings.
  3. Format bool values with %t, not %q or %v on a string, when generating the filter.

Example fix

// before
filter := fmt.Sprintf("export == %v", exportStr) // "true"
// after
filter := fmt.Sprintf("export == %t", exportBool)
Defensive patterns

Strategy: type-guard

Validate before calling

if _, ok := exportValue.(bool); !ok {
    return fmt.Errorf("export filter value must be a bool, got %T", exportValue)
}

Type guard

func isBool(v any) bool {
    _, ok := v.(bool)
    return ok
}

Try / catch

if _, err := store.ListAccessGrants(ctx, filter); err != nil {
    if strings.Contains(err.Error(), "export value must be a boolean") {
        return status.Error(codes.InvalidArgument, "export must be true or false, unquoted")
    }
    return err
}

Prevention

When it happens

Trigger: ListAccessGrants filter like `export == "true"`, `export == 0`, or `export == null`.

Common situations: Same as the unmask case: string-serialized booleans from JSON/env config, over-quoted templated filters, and client SDKs that stringify bools.

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/5dc674b726ea604e. Report an issue: GitHub.