XTLS/Xray-core · error · errors.Error

proxy is not a UserManager

Error message

proxy is not a UserManager

What it means

Returned by AddUserOperation.ApplyInbound (app/proxyman/command/command.go:45) when the inbound handler's proxy does not implement proxy.UserManager. Only user-capable protocols (VMess, VLESS, Trojan, Shadowsocks, etc.) support runtime AddUser; protocol inbounds like dokodemo-door or a mis-tagged outbound-style handler reject user operations.

Source

Thrown at app/proxyman/command/command.go:45

}

func getInbound(handler inbound.Handler) (proxy.Inbound, error) {
	gi, ok := handler.(proxy.GetInbound)
	if !ok {
		return nil, errors.New("can't get inbound proxy from handler.")
	}
	return gi.GetInbound(), nil
}

// ApplyInbound implements InboundOperation.
func (op *AddUserOperation) ApplyInbound(ctx context.Context, handler inbound.Handler) error {
	p, err := getInbound(handler)
	if err != nil {
		return err
	}
	um, ok := p.(proxy.UserManager)
	if !ok {
		return errors.New("proxy is not a UserManager")
	}
	mUser, err := op.User.ToMemoryUser()
	if err != nil {
		return errors.New("failed to parse user").Base(err)
	}
	return um.AddUser(ctx, mUser)
}

// ApplyInbound implements InboundOperation.
func (op *RemoveUserOperation) ApplyInbound(ctx context.Context, handler inbound.Handler) error {
	p, err := getInbound(handler)
	if err != nil {
		return err
	}
	um, ok := p.(proxy.UserManager)
	if !ok {
		return errors.New("proxy is not a UserManager")
	}

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Target an inbound whose protocol supports users (vless/vmess/trojan/shadowsocks).
  2. Verify the inbound tag with ListInbounds before issuing AddUser.
  3. If you must add users dynamically, ensure the inbound was created through the API with the right settings.

Example fix

// before — dokodemo-door cannot hold users
req := &ModifyInboundRequest{InboundTag: "dokodemo-in", Operation: addUserOp}

// after — add to a VLESS inbound
req := &ModifyInboundRequest{InboundTag: "vless-in", Operation: addUserOp}
Defensive patterns

Strategy: type-guard

Type guard

// check the inbound proxy supports users before AddUser
if p, ok := handler.(proxy.GetInbound); ok {
    if _, ok := p.GetInbound().(proxy.UserManager); ok {
        // safe to add user
    }
}

Try / catch

if err := addOp.ApplyInbound(ctx, handler); err != nil {
    if strings.Contains(err.Error(), "not a UserManager") { continue /* non-user inbound */ } else { return err }
}

Prevention

When it happens

Trigger: Calling the HandlerService API's alterInbound with AddUserOperation for an inbound whose proxy type has no user concept — most often dokodemo-door, socks/http inbound (non-user-managed variants), or liberty/mixed handlers configured without user auth.

Common situations: Panels and automation tools that add users to whatever tag the operator typed; a typo in the tag resolving to the wrong inbound, or the panel assuming every inbound is a multi-user proxy.

Related errors


AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15). Data as JSON: /api/errors/25fe92a651e04c56. Report an issue: GitHub.