Skip to content

[Bug] fallback skips nested proxy-groups when group-level health check is down, even if child nodes are aliveΒ #2588

@nasralbek

Description

@nasralbek

Verify steps

  • I have read the documentation and understand the meaning of all the configuration items I have written, rather than just piling up seemingly useful options or default values.
  • I have carefully reviewed the documentation and have not resolved the issue.
  • I have searched the Issue Tracker for the issue I want to raise and did not find it.
  • I am a non-Chinese user.
  • I have tested with the latest Alpha branch version, and the issue still persists.
  • I have provided the server and client configuration files and processes that can reproduce the issue locally, rather than a sanitized complex client configuration file.
  • I provided the simplest configuration that can be used to reproduce the errors in my report, rather than relying on remote servers or piling on a lot of unnecessary configurations for reproduction.
  • I have provided complete logs, rather than just the parts I think are useful out of confidence in my own intelligence.
  • I have directly reproduced the error using the Mihomo command-line program, rather than using other tools or scripts.

Operating System

MacOS

System Version

macos tahoe 26.3

Mihomo Version

1.19.19

Configuration File

mixed-port: 10808
allow-lan: false
mode: rule
log-level: warning
ipv6: false
sniffer:
  enable: true
  sniff:
    TLS:
      ports:
        - 443
    HTTP:
      ports:
        - 80
      override-destination: true
dns:
  enable: true
  ipv6: false
  listen: 0.0.0.0:1053
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.0/15
  nameserver:
    - tcp://1.1.1.1:53
    - tcp://8.8.8.8:53
  nameserver-policy:
    geosite:private:
      - tcp://77.88.8.8:53
    geosite:category-ru:
      - tcp://77.88.8.8:53

proxies:
  - name: poland1
    type: vless
    server: 
    port: 443
    network: tcp
    udp: true
    tls: true
    servername: 
    reality-opts:
      public-key: G2i-nsQgWiVf52tdCUV-G_VeuCJ3hggwDnTaEAgvg0Y
      short-id: ""
    client-fingerprint: chrome
    uuid: 53114c5a-0be7-4234-97b9-358986e73237
    packet-encoding: xudp
  - name: poland2
    type: vless
    server: 
    port: 443
    network: tcp
    udp: true
    tls: true
    servername: 
    reality-opts:
      public-key: G2i-nsQgWiVf52tdCUV-G_VeuCJ3hggwDnTaEAgvg0Y
      short-id: ""
    client-fingerprint: chrome
    uuid: 53114c5a-0be7-4234-97b9-358986e73237
    packet-encoding: xudp
  - name: russia1
    type: vless
    server: 
    port: 443
    network: tcp
    udp: true
    tls: true
    servername: 
    reality-opts:
      public-key: G2i-nsQgWiVf52tdCUV-G_VeuCJ3hggwDnTaEAgvg0Y
      short-id: ""
    client-fingerprint: chrome
    uuid: 53114c5a-0be7-4234-97b9-358986e73237
    packet-encoding: xudp
  - name: russia2
    type: vless
    server: 
    port: 443
    network: tcp
    udp: true
    tls: true
    servername: 
    reality-opts:
      public-key: G2i-nsQgWiVf52tdCUV-G_VeuCJ3hggwDnTaEAgvg0Y
      short-id: ""
    client-fingerprint: chrome
    uuid: 53114c5a-0be7-4234-97b9-358986e73237
    packet-encoding: xudp
  - name: russia3
    type: vless
    server: 
    port: 443
    network: tcp
    udp: true
    tls: true
    servername: 
    reality-opts:
      public-key: G2i-nsQgWiVf52tdCUV-G_VeuCJ3hggwDnTaEAgvg0Y
      short-id: ""
    client-fingerprint: chrome
    uuid: 53114c5a-0be7-4234-97b9-358986e73237
    packet-encoding: xudp
  - name: russia4
    type: vless
    server: 
    port: 443
    network: tcp
    udp: true
    tls: true
    servername: 
    reality-opts:
      public-key: G2i-nsQgWiVf52tdCUV-G_VeuCJ3hggwDnTaEAgvg0Y
      short-id: ""
    client-fingerprint: chrome
    uuid: 53114c5a-0be7-4234-97b9-358986e73237
    packet-encoding: xudp
  - name: timeweb1
    type: vless
    server: 
    port: 443
    network: tcp
    udp: true
    tls: true
    servername: 
    reality-opts:
      public-key: G2i-nsQgWiVf52tdCUV-G_VeuCJ3hggwDnTaEAgvg0Y
      short-id: ""
    client-fingerprint: chrome
    uuid: 53114c5a-0be7-4234-97b9-358986e73237
    packet-encoding: xudp
  - name: timeweb2
    type: vless
    server: 
    port: 443
    network: tcp
    udp: true
    tls: true
    servername: 
    reality-opts:
      public-key: G2i-nsQgWiVf52tdCUV-G_VeuCJ3hggwDnTaEAgvg0Y
      short-id: ""
    client-fingerprint: chrome
    uuid: 53114c5a-0be7-4234-97b9-358986e73237
    packet-encoding: xudp
  - name: timeweb3
    type: vless
    server: 
    port: 443
    network: tcp
    udp: true
    tls: true
    servername: 
    reality-opts:
      public-key: G2i-nsQgWiVf52tdCUV-G_VeuCJ3hggwDnTaEAgvg0Y
      short-id: ""
    client-fingerprint: chrome
    uuid: 53114c5a-0be7-4234-97b9-358986e73237
    packet-encoding: xudp
  - name: vk1
    type: vless
    server: 
    port: 443
    network: tcp
    udp: true
    tls: true
    servername: 
    reality-opts:
      public-key: G2i-nsQgWiVf52tdCUV-G_VeuCJ3hggwDnTaEAgvg0Y
      short-id: ""
    client-fingerprint: chrome
    uuid: 53114c5a-0be7-4234-97b9-358986e73237
    packet-encoding: xudp
  - name: vk2
    type: vless
    server: 
    port: 443
    network: tcp
    udp: true
    tls: true
    servername: 
    reality-opts:
      public-key: G2i-nsQgWiVf52tdCUV-G_VeuCJ3hggwDnTaEAgvg0Y
      short-id: ""
    client-fingerprint: chrome
    uuid: 53114c5a-0be7-4234-97b9-358986e73237
    packet-encoding: xudp

proxy-groups:
  - name: Sosa
    type: select
    proxies:
      - πŸ‡΅πŸ‡± Poland
      - πŸ‡·πŸ‡Ί Russia
    hidden: false

  - name: poland
    type: load-balance
    strategy: sticky-sessions
    hidden: false
    proxies:
      - poland1
      - poland2
    url: https://www.gstatic.com/generate_204
    interval: 30
    timeout: 5000
    lazy: false
    max-failed-times: 1

  - name: πŸ‡΅πŸ‡± Poland
    type: fallback
    hidden: false
    proxies:
      - poland
      - timeweb1
      - timeweb2
      - timeweb3
      - vk1
      - vk2
    url: https://www.gstatic.com/generate_204
    interval: 30
    timeout: 5000
    lazy: false
    max-failed-times: 1

  - name: πŸ‡·πŸ‡Ί Russia
    type: url-test
    hidden: false
    proxies:
      - russia1
      - russia2
      - russia3
      - russia4
    url: https://www.gstatic.com/generate_204
    interval: 30
    timeout: 5000
    lazy: false
    max-failed-times: 1

rules:
  - GEOSITE,private,DIRECT
  - GEOIP,private,DIRECT,no-resolve
  - GEOSITE,youtube,πŸ‡·πŸ‡Ί Russia
  - DOMAIN,www.google.com,πŸ‡·πŸ‡Ί Russia
  - DOMAIN-SUFFIX,2ip.io,πŸ‡·πŸ‡Ί Russia
  - GEOSITE,category-ru,DIRECT
  - DOMAIN-SUFFIX,webapp.sosa.ink,DIRECT
  - GEOIP,ru,DIRECT,no-resolve
  - DOMAIN-KEYWORD,4pda,Sosa
  - MATCH,Sosa

Description

Summary

fallback currently treats nested proxy-groups as opaque nodes during availability checks.

If a nested group (for example url-test) is marked unhealthy at group level, fallback immediately switches to the next proxy in its list, even when the nested group still has at least one alive child proxy.

Current behavior

For a fallback group with nested groups:

  • availability is checked via proxy.AliveForTestUrl(url) on the nested group itself
  • if that check is false, fallback skips the nested group

Expected behavior

When a fallback item is a proxy-group, availability should be evaluated recursively:

  • if any child proxy inside the nested group is alive -> treat nested group as available
  • only if all descendants are dead -> treat it as unavailable and move to next item

Why this is a bug

This causes premature failover and bypasses nested group logic (especially url-test), which should continue selecting the best alive node internally.

Reproduction Steps

Example scenario

  • πŸ‡΅πŸ‡± Poland is a fallback group
  • first item is nested poland group (url-test) with poland1, poland2
  • if poland group-level alive state is false but poland1 is alive:
    • actual: fallback jumps to timeweb1
    • expected: fallback keeps poland, and url-test inside poland chooses alive child

Logs

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions