MHSanaei/3x-ui · error
node has no API token configured
Error message
node has no API token configured
What it means
Remote.do refuses to send when the node record has no ApiToken AND TlsVerifyMode is not 'mtls'. Every node-auth mode except mutual TLS uses a bearer token, so an empty token means the request cannot be authenticated and would surface later as a confusing 401. Failing client-side with this explicit error pinpoints the missing configuration. mtls nodes are exempt because the client certificate itself carries identity.
Source
Thrown at internal/web/runtime/remote.go:181
return "", fmt.Errorf("invalid node port %d", r.node.Port)
}
bp := r.node.BasePath
if !strings.HasSuffix(bp, "/") {
bp += "/"
}
u := &url.URL{
Scheme: scheme,
Host: net.JoinHostPort(addr, strconv.Itoa(r.node.Port)),
Path: bp,
}
return u.String(), nil
}
func (r *Remote) do(ctx context.Context, method, path string, body any) (*envelope, error) {
// mtls nodes authenticate via the client certificate, so a bearer token is
// optional for them; every other mode still requires one.
if r.node.ApiToken == "" && r.node.TlsVerifyMode != "mtls" {
return nil, errors.New("node has no API token configured")
}
base, err := r.baseURL()
if err != nil {
return nil, err
}
target := base + strings.TrimPrefix(path, "/")
var (
bodyBytes []byte
contentType string
)
switch b := body.(type) {
case nil:
case url.Values:
bodyBytes = []byte(b.Encode())
contentType = "application/x-www-form-urlencoded"
default:View on GitHub (pinned to ad32144c42)
Solutions
- Copy the API token from the remote panel and save it on the node record
- If the node genuinely uses mutual TLS, set TlsVerifyMode='mtls' so certificate auth is used instead
- Validate at node-save time that token is non-empty unless mode is mtls, so the error surfaces in the form rather than at dispatch
Example fix
// before node.ApiToken = "" node.TlsVerifyMode = "" // after node.ApiToken = remoteToken // from remote panel // or: node.TlsVerifyMode = "mtls" with client cert configured
Defensive patterns
Strategy: validation
Validate before calling
if node.ApiToken == "" && node.TlsVerifyMode != "mtls" {
return errors.New("save an API token on the node, or switch it to mtls auth")
} Try / catch
if _, err := remote.Do(ctx, method, path, body); err != nil {
if strings.Contains(err.Error(), "no API token configured") {
// fill node.ApiToken from the remote panel and retry once
}
} Prevention
- Require a non-empty token at node save time unless TlsVerifyMode is mtls
- Copy tokens directly from the remote panel UI to avoid paste errors
- After switching a node off mtls, always (re)set the bearer token
When it happens
Trigger: Creating a node without pasting its API token (empty string saved); token field cleared during an edit; switching a node from mtls to token mode without adding the token.
Common situations: New node setup where the operator skipped the token step; copy-paste dropping the token; node templates defaulting to empty token.
Related errors
- remote returned success=false: {msg}
- node {name} is disabled
- XUI_DB_TYPE=postgres but XUI_DB_DSN is empty
- destination DSN is required
- source DSN is required
AI-assisted analysis of MHSanaei/3x-ui@ad32144c42 (2026-08-15).
Data as JSON: /api/errors/820c8089723a161f.
Report an issue: GitHub.