charmbracelet/crush · error

error resolving working directory: %w

Error message

error resolving working directory: %w

What it means

filepath.Abs(workingDir) failed while resolving the view tool's working directory to an absolute path. filepath.Abs rarely fails (it uses os.Getwd when the path is relative), so this usually means the current working directory is unavailable — e.g. the process's cwd was deleted.

Source

Thrown at internal/agent/tools/view.go:118

		viewDescription(),
		func(ctx context.Context, params ViewParams, call fantasy.ToolCall) (fantasy.ToolResponse, error) {
			if params.FilePath == "" {
				return fantasy.NewTextErrorResponse("file_path is required"), nil
			}

			// Handle builtin skill files (crush: prefix).
			if strings.HasPrefix(params.FilePath, skills.BuiltinPrefix) {
				resp, err := readBuiltinFile(params, skillTracker)
				return resp, err
			}

			// Handle relative paths
			filePath := filepathext.SmartJoin(workingDir, params.FilePath)

			// Check if file is outside working directory and request permission if needed
			absWorkingDir, err := filepath.Abs(workingDir)
			if err != nil {
				return fantasy.ToolResponse{}, fmt.Errorf("error resolving working directory: %w", err)
			}

			absFilePath, err := filepath.Abs(filePath)
			if err != nil {
				return fantasy.ToolResponse{}, fmt.Errorf("error resolving file path: %w", err)
			}

			relPath, err := filepath.Rel(absWorkingDir, absFilePath)
			isOutsideWorkDir := err != nil || strings.HasPrefix(relPath, "..")
			isSkillFile := isInSkillsPath(absFilePath, skillsPaths)

			sessionID := GetSessionFromContext(ctx)
			if sessionID == "" {
				return fantasy.ToolResponse{}, fmt.Errorf("session ID is required for accessing files outside working directory")
			}

			// Request permission for files outside working directory, unless it's a skill file.
			if isOutsideWorkDir && !isSkillFile {

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Pass an absolute path as workingDir to NewViewTool so os.Getwd is never needed
  2. Ensure the process's original cwd still exists for the process lifetime
  3. Restart the process from a valid directory
  4. Recreate the deleted directory

Example fix

// before
NewViewTool(lsp, perms, ft, st, "./", skillPaths...) // relies on os.Getwd
// after
abs, _ := filepath.Abs("./") // resolve once at startup, while cwd is valid
NewViewTool(lsp, perms, ft, st, abs, skillPaths...)
Defensive patterns

Strategy: validation

Validate before calling

if !filepath.IsAbs(workingDir) {
    if _, err := os.Getwd(); err != nil {
        return fmt.Errorf("cannot resolve relative workingDir: %w", err)
    }
}

Type guard

func isUsableDir(dir string) bool {
    abs, err := filepath.Abs(dir)
    return err == nil && func() bool { st, err := os.Stat(abs); return err == nil && st.IsDir() }()
}

Try / catch

var pe *fs.PathError
if errors.As(err, &pe) {
    // cwd deleted: recreate it or restart process from a valid directory
}

Prevention

When it happens

Trigger: The tool was constructed with a relative workingDir and the process's current working directory no longer exists or cannot be stat'd, making os.Getwd inside filepath.Abs fail.

Common situations: Working directory removed while the process runs (deleted tmpdir, unmounted volume); launching the process from a since-deleted directory; race with external tooling cleaning up directories.

Related errors


AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29). Data as JSON: /api/errors/0fa2f29fa8910746. Report an issue: GitHub.