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, nil

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Verify the file exists at the given path (ls / stat the path)
  2. Use an absolute path or run from the correct working directory
  3. 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

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


AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05). Data as JSON: /api/errors/4bcdd8c000c70331. Report an issue: GitHub.