vxcontrol/pentagi · error
path is required and cannot be empty
Error message
path is required and cannot be empty
What it means
ReadFile validates its input before doing any container work: an empty path cannot name a file inside the container, so the call is rejected immediately with this error. It is a guard against building a meaningless 'cat ''' command.
Source
Thrown at backend/pkg/tools/terminal.go:331
results := dst.String()
// Style system output with color coding
styledOutput := fmt.Sprintf("%s%s%s%s", ansiColorSystemMsg, results, ansiColorReset, ansiLineTerminator)
_, err = t.tlp.PutMsg(ctx, database.TermlogTypeStdout, styledOutput, t.containerID, t.taskID, t.subtaskID)
if err != nil {
return "", fmt.Errorf("failed to put terminal log (stdout): %w", err)
}
if results == "" {
results = "Command completed successfully with exit code 0. No output produced (silent success)"
}
return results, nil
}
func (t *terminal) ReadFile(ctx context.Context, flowID int64, path string) (string, error) {
if path == "" {
return "", fmt.Errorf("path is required and cannot be empty")
}
cwd := docker.WorkFolderPathInContainer
escapedPath := strings.ReplaceAll(path, "'", "'\"'\"'")
catCommand := fmt.Sprintf("cat '%s'", escapedPath)
// Format read file command with styling
styledCommand := fmt.Sprintf("%s $ %s%s%s%s", cwd, ansiColorInputCmd, catCommand, ansiColorReset, ansiLineTerminator)
_, err := t.tlp.PutMsg(ctx, database.TermlogTypeStdin, styledCommand, t.containerID, t.taskID, t.subtaskID)
if err != nil {
return "", fmt.Errorf("failed to put terminal log (read file cmd): %w", err)
}
content, err := t.readFileFromContainer(ctx, flowID, path)
if err != nil {
return "", err
}
// Style file content outputView on GitHub (pinned to ea665308ba)
Solutions
- Provide a valid absolute path inside the container (e.g. /home/user/report.txt)
- Validate/trim the path at the call site before invoking ReadFile
- If path comes from tool arguments, enforce non-empty in the tool's input schema/validation
Example fix
// before
content, err := term.ReadFile(ctx, flowID, path) // path == ""
// after
path = strings.TrimSpace(path)
if path == "" {
return errors.New("cannot read file: path is empty")
}
content, err := term.ReadFile(ctx, flowID, path) Defensive patterns
Strategy: validation
Validate before calling
func safeReadFile(ctx context.Context, term Terminal, flowID int64, path string) (string, error) {
path = strings.TrimSpace(path)
if path == "" {
return "", errors.New("path is required")
}
return term.ReadFile(ctx, flowID, path)
} Type guard
func validPath(path string) bool {
return strings.TrimSpace(path) != ""
} Try / catch
content, err := term.ReadFile(ctx, flowID, path)
if err != nil && strings.Contains(err.Error(), "path is required") {
return fmt.Errorf("read skipped: %w", err)
} Prevention
- Validate tool-call arguments at the schema layer (non-empty path)
- Trim whitespace before calling ReadFile
- Default optional path fields explicitly
- Never pass through raw LLM-generated arguments unchecked
When it happens
Trigger: Calling terminal.ReadFile(ctx, flowID, "") — e.g. the caller's path variable was never populated, an upstream tool returned an empty string, or an optional path field was not defaulted.
Common situations: LLM agent invokes the read-file tool with a missing/blank path argument; config or task data lacking a file field; string trimming reducing a value to "".
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- container path '%s' is not a directory
- invalid blob hash %q
- path must not be empty
- input must not be empty
- diff is required and cannot be empty
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/a53890ea9fcc9069.
Report an issue: GitHub.