{"record":{"id":"4e994ffba2b4f635","repo":"v2rayA/v2rayA","slug":"you-cannot-ping-a-subscription","errorCode":null,"errorMessage":"you cannot ping a subscription","messagePattern":"you cannot ping a subscription","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"service/db/configure/which.go","lineNumber":176,"sourceCode":"\tcase SubscriptionServerType:\n\t\treturn another.TYPE == w.TYPE &&\n\t\t\tanother.Sub == w.Sub &&\n\t\t\tanother.ID == w.ID &&\n\t\t\tanother.Outbound == w.Outbound\n\tcase ServerType:\n\t\treturn another.TYPE == w.TYPE &&\n\t\t\tanother.ID == w.ID &&\n\t\t\tanother.Outbound == w.Outbound\n\tcase SubscriptionType:\n\t\treturn another.TYPE == w.TYPE &&\n\t\t\tanother.ID == w.ID\n\tdefault:\n\t\treturn false\n\t}\n}\nfunc (w *Which) Ping(timeout time.Duration) (err error) {\n\tif w.TYPE == SubscriptionType {\n\t\treturn fmt.Errorf(\"you cannot ping a subscription\")\n\t}\n\ttsr, err := w.LocateServerRaw()\n\tif err != nil {\n\t\treturn\n\t}\n\t//BEGIN\n\thost := tsr.ServerObj.GetHostname()\n\tif net.ParseIP(host) == nil {\n\t\tvar hosts []string\n\t\thosts, err = resolv.LookupHost(host)\n\t\tif err != nil || len(hosts) <= 0 {\n\t\t\tif err != nil {\n\t\t\t\tw.Latency = err.Error()\n\t\t\t} else {\n\t\t\t\tw.Latency = \"querying dns failed: \" + host\n\t\t\t}\n\t\t\treturn\n\t\t}","sourceCodeStart":158,"sourceCodeEnd":194,"githubUrl":"https://github.com/v2rayA/v2rayA/blob/71e5442fc548c05680ee55eae943e6c0afe9ac51/service/db/configure/which.go#L158-L194","documentation":"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).","triggerScenarios":"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}).","commonSituations":"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.","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."],"exampleFix":"// before\nw := configure.Which{TYPE: configure.SubscriptionType, Sub: subIdx}\nerr := w.Ping(timeout)\n// after\nif w.TYPE == configure.SubscriptionType {\n    w = configure.Which{TYPE: configure.SubscriptionServerType, Sub: subIdx, ID: 1}\n}\nerr := w.Ping(timeout)","handlingStrategy":"validation","validationCode":"if w.TYPE == configure.SubscriptionType {\n    return errors.New(\"select an individual server to ping, not a subscription\")\n}\nerr := w.Ping(10 * time.Second)","typeGuard":"func isPingable(w *configure.Which) bool {\n    return w.TYPE == configure.ServerType || w.TYPE == configure.SubscriptionServerType\n}","tryCatchPattern":"if err := w.Ping(timeout); err != nil {\n    if strings.Contains(err.Error(), \"you cannot ping a subscription\") {\n        // expand subscription into its servers and ping those instead\n        return nil\n    }\n    return err\n}","preventionTips":["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"],"tags":["v2ray","ping","invalid-operation"],"backgroundTag":"invalid-operation-for-type","analyzedSha":"71e5442fc548c05680ee55eae943e6c0afe9ac51","analyzedAt":"2026-09-05T20:04:37.459Z","contentChangedAt":"2026-09-05T20:04:37.459Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}