v2rayA/v2rayA · error

SetRemove: unsupported bucket/key: %s/%s

Error message

SetRemove: unsupported bucket/key: %s/%s

What it means

SetRemove is a thin wrapper over the SQLite-backed set store in v2rayA. It only supports the literal bucket/key combination "outbounds/names" (backed by the outbound_names table); any other bucket/key pair falls into the default switch branch and returns this error. It is an internal API-contract error: the caller passed a bucket/key the store has no implementation for.

Source

Thrown at service/db/setOp.go:52

// SetRemove removes members from a set identified by key.
func SetRemove(bucket string, key string, val interface{}) (err error) {
	db := GetDB()

	switch bucket + "/" + key {
	case "outbounds/names":
		name, ok := val.(string)
		if !ok {
			return fmt.Errorf("SetRemove: outbound name must be a string")
		}
		// Delete related connections and settings first
		_, _ = db.Exec("DELETE FROM outbound_connections WHERE outbound_name = ?", name)
		_, _ = db.Exec("DELETE FROM outbound_settings WHERE outbound_name = ?", name)
		// Delete the outbound name
		_, err = db.Exec("DELETE FROM outbound_names WHERE name = ?", name)
		return err

	default:
		return fmt.Errorf("SetRemove: unsupported bucket/key: %s/%s", bucket, key)
	}
}

// SetIsMember checks if a member exists in a set.
func SetIsMember(bucket string, key string, member string) (bool, error) {
	db := GetDB()

	switch bucket + "/" + key {
	case "outbounds/names":
		var count int
		err := db.QueryRow("SELECT COUNT(*) FROM outbound_names WHERE name = ?", member).Scan(&count)
		if err != nil {
			return false, err
		}
		return count > 0, nil

	default:
		return false, fmt.Errorf("SetIsMember: unsupported bucket/key: %s/%s", bucket, key)

View on GitHub (pinned to 71e5442fc5)

Solutions

  1. Use bucket="outbounds" and key="names" exactly: SetRemove("outbounds", "names", name)
  2. If you need a new set bucket, add a case to the switch in service/db/setOp.go SetRemove before calling it
  3. Check the caller (RemoveOutbound) passes constants, not hand-typed literals

Example fix

// before
db.SetRemove("outbound", "names", name)
// after
db.SetRemove("outbounds", "names", name)
Defensive patterns

Strategy: validation

Validate before calling

func validSetTarget(bucket, key string) bool {
    return bucket == "outbounds" && key == "names"
}
if !validSetTarget(bucket, key) { return errors.New("unsupported bucket/key") }

Try / catch

if err := db.SetRemove("outbounds", "names", name); err != nil {
    if strings.HasPrefix(err.Error(), "SetRemove: unsupported") {
        // fix call site bucket/key constants
    }
    return err
}

Prevention

When it happens

Trigger: Calling SetRemove (directly or via RemoveOutbound) with any bucket or key other than bucket="outbounds", key="names", e.g. SetRemove("outbound", "names", name), SetRemove("outbounds", "name", name), or a misspelled bucket.

Common situations: New code extending the DB layer assumes other buckets are supported; refactors renamed the bucket/key strings; callers ported from the old bolt/boltdb storage which supported more buckets.

Related errors


AI-assisted analysis of v2rayA/v2rayA@71e5442fc5 (2026-09-05). Data as JSON: /api/errors/f55179f48cc77092. Report an issue: GitHub.