googleapis/mcp-toolbox · error
unable to read config file at %q: %w
Error message
unable to read config file at %q: %w
What it means
LoadAndMergeConfigs reads each file with os.ReadFile before parsing. This error wraps any OS-level read failure (ENOENT, EACCES, EISDIR, etc.) together with the file path, so the user knows which config file could not be read.
Source
Thrown at cmd/internal/config.go:511
if genericService, ok := authService.(generic.Config); ok && genericService.McpEnabled {
mcpEnabledAuthServers = append(mcpEnabledAuthServers, name)
}
}
if len(mcpEnabledAuthServers) > 1 {
return Config{}, fmt.Errorf("multiple authServices with mcpEnabled=true detected: %s. Only one MCP authorization server is currently supported", strings.Join(mcpEnabledAuthServers, ", "))
}
return merged, nil
}
// LoadAndMergeConfigs loads multiple YAML files and merges them
func (p *ConfigParser) LoadAndMergeConfigs(ctx context.Context, filePaths []string) (Config, error) {
var configs []Config
for _, filePath := range filePaths {
buf, err := os.ReadFile(filePath)
if err != nil {
return Config{}, fmt.Errorf("unable to read config file at %q: %w", filePath, err)
}
config, err := p.ParseConfig(ctx, buf)
if err != nil {
return Config{}, fmt.Errorf("unable to parse config file at %q: %w", filePath, err)
}
configs = append(configs, config)
}
if len(configs) == 0 {
return Config{}, fmt.Errorf("no YAML files found")
}
if len(configs) > 1 {
mergedFile, err := mergeConfigs(configs...)
if err != nil {
return Config{}, fmt.Errorf("unable to merge config files: %w", err)
}
return mergedFile, nilView on GitHub (pinned to 8cc6e09de2)
Solutions
- Verify the file exists at the given path (ls / stat the path)
- Use an absolute path or run from the correct working directory
- Fix file permissions (chmod) or ensure the file is mounted/copied into the container
Example fix
// before toolbox --config-file ./confg.yaml # typo // after toolbox --config-file ./config.yaml
Defensive patterns
Strategy: try-catch
Validate before calling
for _, f := range filePaths {
if info, err := os.Stat(f); err != nil || info.IsDir() {
return fmt.Errorf("config file %q missing or is a directory", f)
}
} Try / catch
cfg, err := parser.LoadAndMergeConfigs(ctx, files)
if err != nil {
var pe *fs.PathError
if errors.As(err, &pe) {
log.Printf("cannot read %s: %v", pe.Path, pe.Err)
}
return err
} Prevention
- Use absolute paths for config files
- Verify file existence in startup scripts before launching the toolbox
- Ensure config files are copied/mounted into containers
When it happens
Trigger: os.ReadFile fails for one of the filePaths passed to LoadAndMergeConfigs: file does not exist, no read permission, or the path is a directory.
Common situations: Typos in the --config-file path; running the toolbox from a different working directory with a relative path; container images missing the mounted config file; wrong file permissions.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- unable to access config folder at %q: %w
- path %q is not a directory
- error finding YAML files in %q: %w
- error finding YML files in %q: %w
- no YAML files found
AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05).
Data as JSON: /api/errors/4bcdd8c000c70331.
Report an issue: GitHub.