Skip to content

bug(web): git command failures are reported as empty successful status/diff #340

Description

@MicroMilo

Summary

ProjectGitService captures stdout, stderr, and the git process exit code, but status() and diff() ignore non-zero exit codes and parse only stdout. When git fails, the web API can return HTTP 200 with an empty status or empty diff instead of surfacing the failure.

Code path

Producer / parser / feedback anchors:

  • src/adapters/web/projectGit.ts:32-36 declares the runner result shape as { stdout, stderr, code }.
  • src/adapters/web/projectGit.ts:45-47 runs git status --porcelain=v2 --branch and parses only stdout.
  • src/adapters/web/projectGit.ts:50-56 runs git diff and returns only stdout as diff.
  • src/adapters/web/projectGit.ts:59-79 captures the child process code, stdout, and stderr.
  • src/adapters/web/httpRouter.ts:99-109 sends /git/status and /git/diff service results with HTTP 200.
  • src/adapters/web/httpRouter.ts:112-118 only reports an error if the service throws.
  • src/gateway/server/GatewayServer.ts:95-100 binds /api/web/* to handleWebApiRequest.

Steps to reproduce

Validation level: dynamic minimal reproduction plus source control-flow confirmation.

Create a ProjectGitService pointing at a directory that is not a git repository and call status() / diff():

const svc = new ProjectGitService({ projectRoot: nonGitTempDir });
console.log(await svc.status());
console.log(await svc.diff("x.ts"));

Observed local output:

status {"files":[]}
diff {"path":"x.ts","diff":""}

A fake runner that explicitly returns code: 128 and stderr: "fatal: not a git repository" produces the same successful empty objects:

status {"files":[]}
diff {"path":"x.ts","diff":""}

Expected behavior

A non-zero git process exit code should be treated as a failed git operation. The service should preserve stderr and the API should return an error response instead of an empty successful result.

Actual behavior

The non-zero code and stderr are discarded. Empty stdout is interpreted as a valid empty status/diff, and the HTTP route would serialize that as success.

Existing coverage

I checked current issues/PRs for ProjectGitService, parsePorcelainV2, projectGit.ts, httpRouter.ts, /api/web/projects, git status, and git diff; no same-root issue/PR was found.

This is separate from #254 / #285, which cover web-search env API key resolution and do not touch git process failure feedback.

Suggested fix

Make the service throw on code !== 0, preserving enough context for API feedback. For example, centralize runner result handling before parsing stdout:

const result = await this.run(args);
if (result.code !== 0) {
  throw new Error(result.stderr || `git ${args[0]} failed with exit code ${result.code}`);
}

Then map that error to a clear HTTP response in httpRouter rather than returning HTTP 200.

Suggested tests

  • ProjectGitService.status() throws or returns an error when runner returns code: 128.
  • ProjectGitService.diff() throws or returns an error when runner returns code: 128.
  • The error preserves stderr such as fatal: not a git repository.
  • The /git/status and /git/diff HTTP routes return an error response when the service reports git failure.
  • Successful porcelain/diff output continues to parse as before.

Submitted with Codex.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions