alibaba/open-code-review · error

--output directory does not exist: %s

Error message

--output directory does not exist: %s

What it means

resolveOutputWriter validates the --output target before creating a writer. If the parent directory of the requested output path cannot be stat'ed or is not a directory, it refuses to proceed with this error, because writing the review result would fail. The lazyFileWriter defers creation until Close, so a bad parent directory would only surface late; this check fails fast.

Source

Thrown at cmd/opencodereview/shared.go:584

// 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() int64
	TotalCacheReadTokens() int64
	TotalCacheWriteTokens() int64
	Warnings() []agent.AgentWarning
	// ProjectSummary is the markdown project-level summary produced by

View on GitHub (pinned to 5cf97d0d15)

Solutions

  1. Create the parent directory first: mkdir -p $(dirname <output-path>)
  2. Verify the output path spelling and that its parent exists and is a directory (ls -ld $(dirname <path>))
  3. Point --output at an existing directory's file path instead of a not-yet-created tree
  4. If the intent was to dump to stdout, omit --output entirely

Example fix

// before
ocr review --from main --to HEAD --output reports/review.md   # reports/ missing
// after
mkdir -p reports && ocr review --from main --to HEAD --output reports/review.md
Defensive patterns

Strategy: validation

Validate before calling

out="reports/review.md"; dir=$(dirname "$out"); if [ ! -d "$dir" ]; then mkdir -p "$dir" || exit 1; fi; ocr review --from main --to HEAD --output "$out"

Type guard

null

Try / catch

if ! ocr review ... --output "$out" 2>err.log; then grep -q 'directory does not exist' err.log && { mkdir -p "$(dirname "$out")"; ocr review ... --output "$out"; }; fi

Prevention

When it happens

Trigger: Running review/scan with --output set to a path whose parent directory does not exist (e.g. --output reports/ocr.md when ./reports was never created), a parent that is actually a file, or a path under a non-mounted/nonexistent volume. Also covered by tests TestResolveOutputWriter_MissingParent and the anonymous caller.

Common situations: Typing a new subdirectory name that was never mkdir'ed, typos in the output path, CI pipelines where the artifacts directory is not pre-created, or pointing output at a path inside a file (e.g. --output docs/README.md/x.md).

Related errors


AI-assisted analysis of alibaba/open-code-review@5cf97d0d15 (2026-09-02). Data as JSON: /api/errors/1883431e8d415c7b. Report an issue: GitHub.