XTLS/Xray-core · error · errors.Error
unable to create log handler for
Error message
unable to create log handler for
What it means
createHandler looks up a creator function in handlerCreatorMap by LogType; an unknown/unregistered type yields this error with the offending logType embedded. Console and File creators are registered in init(); any other value (including an unparsed string form) has no handler.
Source
Thrown at app/log/log_creator.go:39
func RegisterHandlerCreator(logType LogType, f HandlerCreator) error {
if f == nil {
return errors.New("nil HandlerCreator")
}
handlerCreatorMapLock.Lock()
defer handlerCreatorMapLock.Unlock()
handlerCreatorMap[logType] = f
return nil
}
func createHandler(logType LogType, options HandlerCreatorOptions) (log.Handler, error) {
handlerCreatorMapLock.RLock()
defer handlerCreatorMapLock.RUnlock()
creator, found := handlerCreatorMap[logType]
if !found {
return nil, errors.New("unable to create log handler for ", logType)
}
return creator(logType, options)
}
func init() {
common.Must(RegisterHandlerCreator(LogType_Console, func(lt LogType, options HandlerCreatorOptions) (log.Handler, error) {
return log.NewLogger(log.CreateStdoutLogWriter()), nil
}))
common.Must(RegisterHandlerCreator(LogType_File, func(lt LogType, options HandlerCreatorOptions) (log.Handler, error) {
creator, err := log.CreateFileLogWriter(options.Path)
if err != nil {
return nil, err
}
return log.NewLogger(creator), nil
}))
common.Must(RegisterHandlerCreator(LogType_None, func(lt LogType, options HandlerCreatorOptions) (log.Handler, error) {View on GitHub (pinned to 7d214f8b09)
Solutions
- Use only 'console' or 'file' as the log type in the config
- If a custom handler type is needed, call RegisterHandlerCreator for that LogType before creating the log instance
- Rebuild/upgrade so the binary and the config's log type vocabulary match
Example fix
// before (embedding Xray-core) logType := LogType(42) // unregistered handler, err := createHandler(logType, options) // error // after logType := LogType_File handler, err := createHandler(logType, options)
Defensive patterns
Strategy: validation
Validate before calling
// Restrict config values to registered handler types before creating the logger:
switch logType {
case LogType_Console, LogType_File:
// ok
default:
return fmt.Errorf("unsupported log type: %v", logType)
} Type guard
func isRegisteredLogType(t LogType) bool {
return t == LogType_Console || t == LogType_File
} Prevention
- Only use 'console' and 'file' log types in shipped configs
- Register custom handler creators before any logger creation when embedding
- Keep config schema and binary version in sync to avoid unknown enum values
When it happens
Trigger: RegisterHandlerCreator was never called for the requested LogType — e.g. a config/protobuf supplies a LogType enum value outside LogType_Console/LogType_File, or a custom build skipped the init() registrations.
Common situations: Version skew where a newer config format carries a log type this binary does not know; typos when constructing LogType programmatically; stripped builds that exclude the default handler registrations.
Related errors
- Log Mask: ipv4 mask must be divisible by 8 and between 0-32
- not a Service.
- Dispatcher: Invalid destination.
- FakeDNSEngine is not initialized, but such a sniffer is used
- Failed to convert address to Net IP.
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/f42d60a0c406ce66.
Report an issue: GitHub.