alibaba/open-code-review · error
--output %q is a directory
Error message
--output %q is a directory
What it means
resolveOutputWriter validates the --output path up front and rejects a path that currently exists as a directory with `--output %q is a directory`. This pre-flight check prevents lazyFileWriter from failing later (os.Create would return EISDIR) so the user gets a clear message immediately.
Source
Thrown at cmd/opencodereview/shared.go:580
return w.file.Close()
}
// resolveOutputWriter resolves the --output target into a writer plus a
// cleanup function.
// - "" or "-" → os.Stdout with a no-op cleanup (colors preserved, no hint)
// - otherwise → a lazyFileWriter over os.Create(path), deferred until the
// first Write; text format wraps the file in stripAnsiWriter so ANSI
// colors never reach the result file.
//
// Fail-fast checks (directory target, missing parent) run here without
// creating or truncating anything; deeper errors (permissions, disk) surface
// on the first Write and fail the command non-zero.
func resolveOutputWriter(path, format string) (io.Writer, func() error, error) {
if path == "" || path == "-" {
return os.Stdout, func() error { return nil }, nil
}
if st, err := os.Stat(path); err == nil && st.IsDir() {
return nil, nil, fmt.Errorf("--output %q is a directory", path)
}
parent := filepath.Dir(path)
if st, err := os.Stat(parent); err != nil || !st.IsDir() {
return nil, nil, fmt.Errorf("--output directory does not exist: %s", parent)
}
w := &lazyFileWriter{path: path, strip: !isMachineReadable(format)}
return w, w.Close, nil
}
// ResultProvider abstracts the metadata both internal/agent.Agent and
// internal/scan.Agent expose post-run, so emitRunResult can finalize
// either without knowing which kind it has.
type ResultProvider interface {
Diffs() []model.Diff
FilesReviewed() int64
TotalInputTokens() int64
TotalOutputTokens() int64
TotalTokensUsed() int64View on GitHub (pinned to 5cf97d0d15)
Solutions
- Pass a full file path, e.g. --output ./reports/review.md
- If you meant stdout, use --output - or omit --output
- Remove or rename the directory if it was created by mistake
Example fix
// before ocr review --output ./reports // after ocr review --output ./reports/review.md
Defensive patterns
Strategy: validation
Validate before calling
if out != "" && out != "-" {
if st, err := os.Stat(out); err == nil && st.IsDir() {
return fmt.Errorf("--output must be a file path, got directory %s", out)
}
} Prevention
- Always pass a filename, not a directory, to --output
- Use --output - for stdout when a file target is ambiguous
- In scripts, build output paths with filepath.Join(dir, "review.md") rather than passing dir directly
When it happens
Trigger: ocr review/scan run with --output set to a directory path such as `--output ./reports` or `--output .` instead of a file path.
Common situations: Shell completion or copy-paste yielding a directory; intending 'write into this directory' but passing the directory itself; a stale script where the target name became a directory in a later step.
Related errors
- "%q %s" (+ positional signature, valid values, usage line, e
- read background file %q: %w
- background file %q is a directory, not a file
- background file %q is %d bytes, exceeding the maximum of %d
- MCP server %q not found
AI-assisted analysis of alibaba/open-code-review@5cf97d0d15 (2026-09-02).
Data as JSON: /api/errors/1e9653c68771707a.
Report an issue: GitHub.