XTLS/Xray-core · error
failed to read config:
Error message
failed to read config:
What it means
The JSON config loader (registered for the "json" format) fails when confloader.LoadConfig cannot produce a reader for one of the argument paths. confloader.LoadConfig dispatches to external.FetchHTTPContent for http(s)/socket-looking targets and to local file reading otherwise, so this error wraps either a network fetch failure or a filesystem error (missing file, permission denied).
Source
Thrown at main/json/json.go:28
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/infra/conf"
"github.com/xtls/xray-core/infra/conf/serial"
"github.com/xtls/xray-core/main/confloader"
)
func init() {
common.Must(core.RegisterConfigLoader(&core.ConfigFormat{
Name: "JSON",
Extension: []string{"json"},
Loader: func(input interface{}) (*core.Config, error) {
switch v := input.(type) {
case cmdarg.Arg:
cf := &conf.Config{}
for i, arg := range v {
errors.LogInfo(context.Background(), "Reading config: ", arg)
r, err := confloader.LoadConfig(arg)
if err != nil {
return nil, errors.New("failed to read config: ", arg).Base(err)
}
c, err := serial.DecodeJSONConfig(r)
if err != nil {
return nil, errors.New("failed to decode config: ", arg).Base(err)
}
if i == 0 {
// This ensure even if the muti-json parser do not support a setting,
// It is still respected automatically for the first configure file
*cf = *c
continue
}
cf.Override(c, arg)
}
return cf.Build()
case io.Reader:
if serial.UseStrictJSON {
cfg, err := serial.DecodeJSONConfigStrict(v)
if err != nil {View on GitHub (pinned to 7d214f8b09)
Solutions
- Confirm the file exists at the exact path printed in the message (it includes the failing arg)
- Fix permissions: chmod 644 and ensure the running user owns/can read it
- Use absolute paths in service/systemd units where the working directory differs
- If the arg is a URL, debug the underlying fetch error (dial/status/read) chained in Base(err)
Example fix
# before xray run -c conf/config.json # run from another cwd -> failed to read config # after xray run -c /etc/xray/config.json
Defensive patterns
Strategy: validation
Validate before calling
func configReadable(p string) error { fi, err := os.Stat(p); if err != nil { return err }; if fi.IsDir() { return fmt.Errorf("is dir") }; return nil }
for _, p := range paths { if err := configReadable(p); err != nil { log.Fatal(err) } } Type guard
func isLoadableArg(v interface{}) bool { _, ok1 := v.(cmdarg.Arg); _, ok2 := v.(io.Reader); return ok1 || ok2 } Try / catch
if err := runStartXray(); err != nil && strings.Contains(err.Error(), "failed to read config") { os.Exit(1) /* report file from message */ } Prevention
- Use absolute config paths, especially in systemd units
- Run as the service user when verifying read permission
- Keep a pre-deploy step that stats every config path in CI
When it happens
Trigger: Passing a nonexistent path in cmdarg.Arg (e.g. xray run -c ./missing.json), a file without read permission, or a URL-style config target whose fetch failed (dial, status, read errors from errors 541-543 surface here as the chained cause).
Common situations: Wrong working directory making a relative config path unresolvable, typos in filenames, running Xray as a service user that cannot read the config, or remote-config URL failures at boot.
Related errors
- invalid fakedns config
- failed to parse Socks user
- failed to parse socks account
- unknown type
- failed to decode config:
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/47261626bfdd5955.
Report an issue: GitHub.