v2rayA/v2rayA · warning
you cannot ping a subscription
Error message
you cannot ping a subscription
What it means
Which.Ping tests connectivity to the node referenced by this Which. If the Which's TYPE is SubscriptionType — i.e. it points at a whole subscription rather than an individual server — there is nothing to ping, so Ping immediately returns this error instead of attempting a connection. It is a misuse guard: pings only make sense for concrete server entries (ServerType or SubscriptionServerType).
Source
Thrown at service/db/configure/which.go:176
case SubscriptionServerType:
return another.TYPE == w.TYPE &&
another.Sub == w.Sub &&
another.ID == w.ID &&
another.Outbound == w.Outbound
case ServerType:
return another.TYPE == w.TYPE &&
another.ID == w.ID &&
another.Outbound == w.Outbound
case SubscriptionType:
return another.TYPE == w.TYPE &&
another.ID == w.ID
default:
return false
}
}
func (w *Which) Ping(timeout time.Duration) (err error) {
if w.TYPE == SubscriptionType {
return fmt.Errorf("you cannot ping a subscription")
}
tsr, err := w.LocateServerRaw()
if err != nil {
return
}
//BEGIN
host := tsr.ServerObj.GetHostname()
if net.ParseIP(host) == nil {
var hosts []string
hosts, err = resolv.LookupHost(host)
if err != nil || len(hosts) <= 0 {
if err != nil {
w.Latency = err.Error()
} else {
w.Latency = "querying dns failed: " + host
}
return
}View on GitHub (pinned to 71e5442fc5)
Solutions
- Ping an individual server instead: resolve a server under the subscription (e.g. Which{TYPE: SubscriptionServerType, ID: n, Sub: subIndex}) before calling Ping.
- Check w.TYPE == SubscriptionType in the caller and return a friendly message or pick the first server of the subscription.
- If the goal is to test the subscription's address, issue an HTTP GET of the subscription URL directly, not Ping.
Example fix
// before
w := configure.Which{TYPE: configure.SubscriptionType, Sub: subIdx}
err := w.Ping(timeout)
// after
if w.TYPE == configure.SubscriptionType {
w = configure.Which{TYPE: configure.SubscriptionServerType, Sub: subIdx, ID: 1}
}
err := w.Ping(timeout) Defensive patterns
Strategy: validation
Validate before calling
if w.TYPE == configure.SubscriptionType {
return errors.New("select an individual server to ping, not a subscription")
}
err := w.Ping(10 * time.Second) Type guard
func isPingable(w *configure.Which) bool {
return w.TYPE == configure.ServerType || w.TYPE == configure.SubscriptionServerType
} Try / catch
if err := w.Ping(timeout); err != nil {
if strings.Contains(err.Error(), "you cannot ping a subscription") {
// expand subscription into its servers and ping those instead
return nil
}
return err
} Prevention
- Always set Which.TYPE from the configure constants, never raw ints
- In UIs, only enable the ping action for server rows, not subscription rows
- Expand SubscriptionType whiches into SubscriptionServerType entries before batch pings
When it happens
Trigger: Calling w.Ping(timeout) on a Which whose TYPE field is SubscriptionType (selected in a UI list of subscriptions and passed to the ping API, or constructed with Which{TYPE: SubscriptionType}).
Common situations: Front-end passes the subscription row itself to the ping endpoint instead of one of its servers; stale saved Whiches loaded from a which list after data was re-imported so IDs/TYPEs no longer match user intent.
Related errors
- LocateServerRaw: ID exceed range
- LocateServerRaw: ID or Sub exceed range
- LocateServerRaw: invalid TYPE
- ListSet: server at index %d not found
- ListSet: subscription at index %d not found
AI-assisted analysis of v2rayA/v2rayA@71e5442fc5 (2026-09-05).
Data as JSON: /api/errors/4e994ffba2b4f635.
Report an issue: GitHub.