Bug
ao spawn --branch "<invalid name>" (a branch name rejected by git check-ref-format) returns an opaque Internal server error (INTERNAL_ERROR) 500 instead of a 400 validation error.
Analyzed against: 3e64c15 | Confidence: High
Reproduction
ao spawn --project <p> --branch "bad branch name!!" --prompt x
# → Internal server error (INTERNAL_ERROR)
Root Cause
backend/internal/adapters/workspace/gitworktree/workspace.go validateBranch returns fmt.Errorf("gitworktree: invalid branch %q: %w", branch, err) — an untyped error. toAPIError (backend/internal/service/session/service.go) has no matching sentinel, so it hits default and the envelope collapses it to INTERNAL_ERROR 500.
This is the residual of #152 Bug 3: that RCA added ErrWorkspaceBranchNotFetched and ErrWorkspaceBranchCheckedOutElsewhere (now mapped to 400/409), but the invalid-format case — the very first check in validateBranch — was never given a sentinel, so it still 500s.
Fix
Add a ports.ErrWorkspaceBranchInvalid sentinel (mirroring the other two), wrap it in validateBranch, and map it in toAPIError → apierr.Invalid("INVALID_BRANCH", ...). The 400 carries git's own reason for the user.
Impact
User-controllable input (--branch) produces a confusing 500. Completes the "no opaque 500s on workspace branch errors" set from #152. Labels: bug, priority: medium.
Bug
ao spawn --branch "<invalid name>"(a branch name rejected bygit check-ref-format) returns an opaqueInternal server error (INTERNAL_ERROR)500 instead of a 400 validation error.Analyzed against:
3e64c15| Confidence: HighReproduction
Root Cause
backend/internal/adapters/workspace/gitworktree/workspace.govalidateBranchreturnsfmt.Errorf("gitworktree: invalid branch %q: %w", branch, err)— an untyped error.toAPIError(backend/internal/service/session/service.go) has no matching sentinel, so it hitsdefaultand the envelope collapses it toINTERNAL_ERROR500.This is the residual of #152 Bug 3: that RCA added
ErrWorkspaceBranchNotFetchedandErrWorkspaceBranchCheckedOutElsewhere(now mapped to 400/409), but the invalid-format case — the very first check invalidateBranch— was never given a sentinel, so it still 500s.Fix
Add a
ports.ErrWorkspaceBranchInvalidsentinel (mirroring the other two), wrap it invalidateBranch, and map it intoAPIError→apierr.Invalid("INVALID_BRANCH", ...). The 400 carries git's own reason for the user.Impact
User-controllable input (
--branch) produces a confusing 500. Completes the "no opaque 500s on workspace branch errors" set from #152. Labels:bug,priority: medium.