alibaba/open-code-review · error

read tools file %s: %w

Error message

read tools file %s: %w

What it means

Load reads tool definitions either from the built-in defaultToolsJSON (path=="") or from the file at the given path; this error wraps os.ReadFile failures for a custom path. It means the tools config file could not be read at all — not that its contents are invalid.

Source

Thrown at internal/config/toolsconfig/toolsconfig.go:35

	PlanTask   bool            `json:"plan_task"`
	MainTask   bool            `json:"main_task"`
	Definition json.RawMessage `json:"definition"`
}

//go:embed tools.json
var defaultToolsJSON []byte

// Load parses the tools config file. When path is empty, falls back to
// the embedded default tools configuration.
func Load(path string) ([]ToolConfigEntry, error) {
	var data []byte
	var err error
	if path == "" {
		data = defaultToolsJSON
	} else {
		data, err = os.ReadFile(path)
		if err != nil {
			return nil, fmt.Errorf("read tools file %s: %w", path, err)
		}
	}
	var tools []ToolConfigEntry
	if err := json.Unmarshal(data, &tools); err != nil {
		return nil, fmt.Errorf("unmarshal tools file: %w", err)
	}
	return tools, nil
}

// ToolDefsByPhase returns the parsed tool definitions filtered by phase.
// planOnly=true returns only tools with plan_task:true.
// planOnly=false returns only tools with main_task:true.
func (t *ToolConfigEntry) ToolDefsByPhase(planOnly bool) (json.RawMessage, bool) {
	switch {
	case planOnly && t.PlanTask:
		return t.Definition, true
	case !planOnly && t.MainTask:
		return t.Definition, true

View on GitHub (pinned to 5cf97d0d15)

Solutions

  1. Verify the path exists and is a readable file (ls/ll the path), or pass an absolute path
  2. Pass an empty path to fall back to the built-in default tools JSON
  3. Fix filesystem permissions for the user running the tool

Example fix

// before
tools, err := toolsconfig.Load("./tools.json") // file missing
// after
path := "./tools.json"
if _, err := os.Stat(path); err != nil { path = "" } // fall back to defaults
tools, err := toolsconfig.Load(path)
Defensive patterns

Strategy: validation

Validate before calling

info, err := os.Stat(path)
if err != nil || info.IsDir() { return fmt.Errorf("tools file %s unavailable: %w", path, err) }

Try / catch

tools, err := toolsconfig.Load(path)
if err != nil {
    var pathErr *os.PathError
    if errors.As(err, &pathErr) { tools, err = toolsconfig.Load("") /* defaults */ }
    if err != nil { return err }
}

Prevention

When it happens

Trigger: Calling Load(path) with a non-empty path where os.ReadFile fails: file does not exist, permission denied, path is a directory, or an I/O error.

Common situations: Passing a --tools flag with a wrong/relative path from a different working directory; the tools file was deleted or renamed; running under a service account lacking read permission.

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 alibaba/open-code-review@5cf97d0d15 (2026-09-02). Data as JSON: /api/errors/d809b1eae27077eb. Report an issue: GitHub.