MHSanaei/3x-ui · error
remote AddClient: resolve tag %q: %w
Error message
remote AddClient: resolve tag %q: %w
What it means
Wraps the resolveRemoteID failure inside Remote.AddClient: the central panel tried to add a client to an inbound on a node, but could not map the inbound's tag to the node-local inbound ID first. The inner error is either the refresh failure (network/decode, errors 100-109) or the tag-not-found error (107).
Source
Thrown at internal/web/runtime/remote.go:545
// wireFingerprint hashes a wire payload so an unchanged inbound is cheap to detect.
func wireFingerprint(v url.Values) string {
sum := sha256.Sum256([]byte(v.Encode()))
return hex.EncodeToString(sum[:])
}
func (r *Remote) AddUser(ctx context.Context, ib *model.Inbound, _ map[string]any) error {
return r.UpdateInbound(ctx, ib, ib)
}
func (r *Remote) RemoveUser(ctx context.Context, ib *model.Inbound, _ string) error {
return r.UpdateInbound(ctx, ib, ib)
}
func (r *Remote) AddClient(ctx context.Context, ib *model.Inbound, client model.Client) error {
id, err := r.resolveRemoteID(ctx, ib.Tag)
if err != nil {
return fmt.Errorf("remote AddClient: resolve tag %q: %w", ib.Tag, err)
}
payload := map[string]any{
"client": client,
"inboundIds": []int{id},
}
if _, err := r.do(ctx, http.MethodPost, "panel/api/clients/add", payload); err != nil {
return err
}
return nil
}
func (r *Remote) DeleteUser(ctx context.Context, ib *model.Inbound, email string) error {
if email == "" {
return nil
}
id, err := r.resolveRemoteID(ctx, ib.Tag)
if err != nil {
// Can't confirm the delete reached the node — surface it so the callerView on GitHub (pinned to ad32144c42)
Solutions
- Resolve node reachability first if the inner error is a transport/decode failure (see the wrapped message).
- If the inner error is 'not found on node', push/re-save the inbound on the master so the node recreates it, then retry the client add.
- Avoid direct node-side inbound edits that break tag parity with the central panel.
- Run a reconcile for the node to converge inbound state before retrying per-client writes.
Example fix
// before: err: remote AddClient: resolve tag "n2-vmess-in": remote inbound with tag "n2-vmess-in" not found on node edge-2 // after: re-save the inbound on the central panel (re-pushes it to the node), then retry the client add
Defensive patterns
Strategy: retry
Validate before calling
if _, err := remote.ResolveTag(ctx, ib.Tag); err != nil {
return fmt.Errorf("inbound not present on node; push it before adding clients: %w", err)
} Type guard
func isResolveFailure(err error) bool {
return err != nil && strings.Contains(err.Error(), "resolve tag")
} Try / catch
if err := remote.AddClient(ctx, ib, client); err != nil {
if isResolveFailure(err) {
if perr := pushInbound(ctx, ib); perr != nil { return errors.Join(err, perr) }
return remote.AddClient(ctx, ib, client) // one converged retry
}
return err
} Prevention
- Always create/push the inbound on the node before adding clients to it.
- Check node health before bulk client imports on node-assigned inbounds.
- Never rename inbounds directly on nodes.
When it happens
Trigger: Adding a client to a node-assigned inbound whose tag does not exist on the node, or while the node is unreachable so the ID cache cannot be refreshed. The payload (client + inboundIds) is never sent.
Common situations: Client add raced a node-side inbound deletion; node offline mid-operation; tag drifted after out-of-band node edits.
Related errors
- remote inbound with tag %q not found on node %s
- remote DeleteUser: resolve tag %q: %w
- %s %s: %w
- %s %s: HTTP %d: %q
- %s %s: HTTP %d
AI-assisted analysis of MHSanaei/3x-ui@ad32144c42 (2026-08-15).
Data as JSON: /api/errors/03c90ca537c58805.
Report an issue: GitHub.