XTLS/Xray-core · error
failed to read config:
Error message
failed to read config:
What it means
TOML counterpart of the JSON read error: the TOML loader (registered for extension "toml") fails when confloader.LoadConfig cannot obtain a reader for one of the config arguments. Exactly like error 544 but for the TOML path — the cause is either a filesystem failure (missing/unreadable file) or a failed remote fetch (http/socket target).
Source
Thrown at main/toml/toml.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: "TOML",
Extension: []string{"toml"},
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.DecodeTOMLConfig(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:
return serial.LoadTOMLConfig(v)
default:
return nil, errors.New("unknown type")View on GitHub (pinned to 7d214f8b09)
Solutions
- Verify the exact path from the error message exists and is readable (ls -l, run as the service user)
- Use absolute paths in service definitions
- If remote, debug the fetch cause chained in Base(err) (dial/status/read)
- Ensure the file really contains TOML — extension and content must agree
Example fix
# before xray run -c xray.toml # file actually at /etc/xray/xray.toml # after xray run -c /etc/xray/xray.toml
Defensive patterns
Strategy: validation
Validate before calling
for _, p := range tomlPaths { if fi, err := os.Stat(p); err != nil || fi.IsDir() { return err } } Try / catch
if err := startXray(); err != nil && strings.Contains(err.Error(), "failed to read config") { extractFailingArg(err); os.Exit(1) } Prevention
- Use absolute .toml paths in service units
- Verify readability as the runtime user
- Automate TOML linting in CI (taplo)
When it happens
Trigger: xray run -c config.toml where config.toml does not exist, is unreadable by the service user, or where the arg is an http(s)/socket target whose fetch failed.
Common situations: Renaming a .json config to .toml without converting content (then hitting decode instead), wrong path in systemd units, permission issues under hardened service users, remote TOML endpoints down.
Related errors
- failed to read config:
- failed to decode config: {arg}
- failed to read config: {arg}
- failed to get outbound handler with tag: ${tag}
- existing tag found: ${tag}
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/01a9b0f6ba3f5ecd.
Report an issue: GitHub.