Skip to content

fix(server): match project copy errors by _tag instead of instanceof - #43999

Open
miladsoroush wants to merge 1 commit into
anomalyco:devfrom
miladsoroush:patch-1
Open

fix(server): match project copy errors by _tag instead of instanceof#43999
miladsoroush wants to merge 1 commit into
anomalyco:devfrom
miladsoroush:patch-1

Conversation

@miladsoroush

@miladsoroush miladsoroush commented Aug 21, 2026

Copy link
Copy Markdown

Issue for this PR

Closes #43995

Related to #40613, which reports the same symptom (forceRequired false when it should be true) from a different cause — the regex in git.ts only matches English git output. The two are independent: this PR doesn't address the locale case, and fixing the locale case wouldn't address this one.

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

project-copy.ts identifies errors with instanceof, which compares class identity. If @opencode-ai/core is ever loaded twice in one process, the service constructs the error from one copy of the module and the handler tests it against the other, so every check returns false while the code still looks correct.

I hit this in a workspace that path-maps the core specifiers. It won't reproduce on a stock checkout, and since core isn't published, a normal install can't produce two copies — so I'm not claiming this is currently broken for anyone else. The reason I think it's still worth changing: _tag comparison doesn't depend on identity, it's already the pattern used in ~52 places in this codebase (including error handling, e.g. error._tag === "FileSystemError"), and this handler is the outlier.

Six checks changed, plus the now-unused Git import removed. No behaviour change when only one copy of core is loaded.

Impact when the checks do fail

  • forceRequired is dropped from the 400 response, so a client can't tell the user to retry with force after a failed project-copy delete. The operation looks like a plain failure.
  • All five ProjectCopy errors fall through to error.message, surfacing raw git text ("fatal: '...' contains modified or untracked files") instead of the formatted messages.

Both fail silently — instanceof returning false doesn't throw, so nothing surfaces except the degraded response.

How did you verify your code works?

From packages/opencode: bun test test/server/project-copy.test.ts — the "lists directories and manages git worktree copies" case asserts forceRequired: true after deleting a dirty worktree. It passes before and after on a stock checkout. In my path-mapped setup it failed before and passes now. tsgo --noEmit on packages/server is clean.

Screenshots / recordings

N/A, not a UI change.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

### Issue for this PR

Closes anomalyco#43995

Related to anomalyco#40613, which reports the same symptom (forceRequired false when it should be true) from a different cause — the regex in git.ts only matches English git output. The two are independent: this PR doesn't address the locale case, and fixing the locale case wouldn't address this one.

### Type of change

- [x] Bug fix
- [ ] New feature
- [ ] Refactor / code improvement
- [ ] Documentation

### What does this PR do?

`project-copy.ts` identifies errors with `instanceof`, which compares class identity. If
`@opencode-ai/core` is ever loaded twice in one process, the service constructs the error from
one copy of the module and the handler tests it against the other, so every check returns false
while the code still looks correct.

I hit this in a workspace that path-maps the core specifiers. It won't reproduce on a stock
checkout, and since core isn't published, a normal install can't produce two copies — so I'm
not claiming this is currently broken for anyone else. The reason I think it's still worth
changing: `_tag` comparison doesn't depend on identity, it's already the pattern used in ~52
places in this codebase (including error handling, e.g. `error._tag === "FileSystemError"`),
and this handler is the outlier.

Six checks changed, plus the now-unused `Git` import removed. No behaviour change when only
one copy of core is loaded.

### Impact when the checks do fail

- `forceRequired` is dropped from the 400 response, so a client can't tell the user to retry
  with force after a failed project-copy delete. The operation looks like a plain failure.
- All five ProjectCopy errors fall through to `error.message`, surfacing raw git text
  ("fatal: '...' contains modified or untracked files") instead of the formatted messages.

Both fail silently — `instanceof` returning false doesn't throw, so nothing surfaces except
the degraded response.

### How did you verify your code works?

`bun test test/server/project-copy.test.ts` in the server package — the "lists directories and
manages git worktree copies" case asserts `forceRequired: true` after deleting a dirty
worktree. It passes before and after on a stock checkout. In my path-mapped setup it failed
before and passes now. `tsgo --noEmit` on `packages/server` is clean.

### Screenshots / recordings

N/A, not a UI change.

### Checklist

- [x] I have tested my changes locally
- [x] I have not included unrelated changes in this PR
@github-actions

Copy link
Copy Markdown
Contributor

Hey! Your PR title fix-project-copy-tag-matching doesn't follow conventional commit format.

Please update it to start with one of:

  • feat: or feat(scope): new feature
  • fix: or fix(scope): bug fix
  • docs: or docs(scope): documentation changes
  • chore: or chore(scope): maintenance tasks
  • refactor: or refactor(scope): code refactoring
  • test: or test(scope): adding or updating tests

Where scope is the package name (e.g., app, desktop, opencode).

See CONTRIBUTING.md for details.

@github-actions

Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

Based on my search, I found one potentially related PR:

Related PR (not a duplicate):

Why it's related:
The PR description explicitly mentions this (#40606 is related to #40613). Both PRs address the same symptom (forceRequired being false when it should be true) but from different causes:

The description notes these are independent issues — fixing one wouldn't address the other — so they are complementary rather than duplicative.

@miladsoroush miladsoroush changed the title fix-project-copy-tag-matching fix(server): match project copy errors by _tag instead of instanceof Aug 21, 2026
@miladsoroush

Copy link
Copy Markdown
Author

Hey! Your PR title fix-project-copy-tag-matching doesn't follow conventional commit format.

Please update it to start with one of:

  • feat: or feat(scope): new feature
  • fix: or fix(scope): bug fix
  • docs: or docs(scope): documentation changes
  • chore: or chore(scope): maintenance tasks
  • refactor: or refactor(scope): code refactoring
  • test: or test(scope): adding or updating tests

Where scope is the package name (e.g., app, desktop, opencode).

See CONTRIBUTING.md for details.

fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix-project-copy-tag-matching

1 participant