MHSanaei/3x-ui · error
decode web cert files: %w
Error message
decode web cert files: %w
What it means
Returned by Remote.GetWebCertFiles when the node's panel/api/server/getWebCertFiles endpoint answered 200 but env.Obj does not decode into WebCertFiles (the expected cert/key path strings). The node-side handler exists (otherwise error 101/102 would fire), but the payload shape does not match.
Source
Thrown at internal/web/runtime/remote.go:648
// WebCertFiles holds a node's own web TLS certificate and key file paths.
type WebCertFiles struct {
WebCertFile string `json:"webCertFile"`
WebKeyFile string `json:"webKeyFile"`
}
// GetWebCertFiles fetches the node's own web TLS certificate/key file paths so
// the central panel can offer them as the "Set Cert from Panel" default for a
// node-assigned inbound — those paths exist on the node, the central panel's
// don't. See issue #4854.
func (r *Remote) GetWebCertFiles(ctx context.Context) (*WebCertFiles, error) {
env, err := r.do(ctx, http.MethodGet, "panel/api/server/getWebCertFiles", nil)
if err != nil {
return nil, err
}
var files WebCertFiles
if err := json.Unmarshal(env.Obj, &files); err != nil {
return nil, fmt.Errorf("decode web cert files: %w", err)
}
return &files, nil
}
// GetDescendants fetches the node's read-only summaries of the nodes IT
// manages, so this panel can surface them as transitive sub-nodes in a chained
// topology (#4983). Best-effort: an old-build node without the endpoint returns
// an error the caller ignores.
func (r *Remote) GetDescendants(ctx context.Context) ([]model.NodeSummary, error) {
env, err := r.do(ctx, http.MethodGet, "panel/api/server/descendants", nil)
if err != nil {
return nil, err
}
var out []model.NodeSummary
if len(env.Obj) > 0 {
if err := json.Unmarshal(env.Obj, &out); err != nil {
return nil, fmt.Errorf("decode descendants: %w", err)
}View on GitHub (pinned to ad32144c42)
Solutions
- Upgrade the node to the same release as the master — this endpoint is version-coupled (issue #4854 feature).
- curl the endpoint on the node and compare obj's keys with WebCertFiles fields.
- If the node has no cert configured, set the node's own web cert first so the handler returns real paths.
- As a workaround, enter the cert paths manually instead of using the panel-default fetch.
Example fix
// before: old node returns {"obj": null} when no cert is set
// err: decode web cert files: json: cannot unmarshal null into Go value of type runtime.WebCertFiles
// after: upgrade node / configure the node's web cert so obj carries the path strings Defensive patterns
Strategy: fallback
Validate before calling
// Version/feature gate before offering the panel-default cert button
if !nodeSupportsWebCertFiles(n) {
ui.DisableSetCertFromPanel(n.ID) // fall back to manual path entry
} Type guard
func isCertDecodeError(err error) bool {
return err != nil && strings.HasPrefix(err.Error(), "decode web cert files:")
} Try / catch
files, err := nodeSvc.GetWebCertFiles(id)
if err != nil {
if isCertDecodeError(err) {
files = nil // degrade to manual cert path input in the UI
} else {
return err
}
} Prevention
- Upgrade nodes before using cert-from-panel on them (feature is version-coupled, #4854).
- Configure the node's own web cert first so the endpoint returns real paths.
- Keep a manual cert-path fallback in workflows that span mixed versions.
When it happens
Trigger: Invoking 'Set Cert from Panel' for a node-assigned inbound against a node build whose getWebCertFiles returns a different obj shape, obj:null, or an error object inside a success envelope; node version predates the field layout the master expects.
Common situations: Master newer than node (endpoint added recently, layout drifted); node where web cert paths are unset so the handler returns obj with nulls on older builds.
Related errors
- decode inbound list: %w
- %s %s: HTTP %d: %q
- %s %s: %w
- %s %s: HTTP %d
- %s %s: %w (content-length %d, cap %d)
AI-assisted analysis of MHSanaei/3x-ui@ad32144c42 (2026-08-15).
Data as JSON: /api/errors/cc76de80225d5fee.
Report an issue: GitHub.