fix(containers): answer 404 when a path is outside every workspace - #50
Merged
Conversation
/api/containers/attempt-context returned 500 for any directory that is not inside a workspace. It was the single largest source of server errors on a live instance -- 571 of them, and after the SQLite contention fix it was the only remaining source. The failure was not a database failure at all. resolve_container_ref_by_prefix runs a fetch_all that succeeds, matches the requested path against the loaded container refs in memory, and then reported "nothing matched" by manufacturing sqlx::Error::RowNotFound. Both callers mapped that to ApiError::Database, which maps to a generic 500 "An internal error occurred." Editors and MCP clients call these endpoints with whatever directory they were started in, so a path outside every workspace is the ordinary case rather than an exceptional one. Return Option instead, so a logical miss stays distinguishable from a real database error, and let both callers answer 404 -- matching load_context, which already reports a missing workspace that way in the same handler. Observed values that triggered it include /home/miguel and worktrees under /var/tmp/br-lanes, none of which are workspace container refs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
GET /api/containers/attempt-context?ref=<dir>returns 500 for any directory that isn't inside a workspace.On a live instance this was 571 errors — the single largest source of server errors. After the SQLite contention fix (#49) it became the only remaining source:
The client sees
"An internal error occurred. Please try again."It was never a database failure
Workspace::resolve_container_ref_by_prefixdoes this:The query succeeds. The prefix match then runs in memory, finds no workspace containing the path, and manufactures
sqlx::Error::RowNotFoundto mean "no match" — using a database-error type as anOption::None.Both callers then do
.map_err(ApiError::Database), anderror.rsmapsApiError::Database(_)toErrorInfo::internal("DatabaseError")→ 500.So "is this directory a workspace?" answered about a directory that isn't one is reported as a server fault.
Who hits it
Editors and MCP clients call these endpoints with whatever directory they were started in, so a non-workspace path is the ordinary case. Observed
?ref=values, none of which are workspace container refs (those live under/var/tmp/vibe-kanban/worktrees/):?ref=/home/miguel/var/tmp/admin2-lane/wt/var/tmp/br-lanes/receiver-redesign/home/miguel/projects/patricia-monorepo/.wt/starter-credits/var/tmp/chief-worktrees/bc-mobile-filesUpstream: BloopAI/vibe-kanban#3272, open since March.
Change
resolve_container_ref_by_prefixreturnsResult<Option<ContainerInfo>, sqlx::Error>— a logical miss stops masquerading as a database error, and a genuine database error stays distinguishable.get_container_infoandget_context— the only two) answer 404 viaWorkspaceError::WorkspaceNotFound.404 rather than a new error variant because
load_context, two lines below in the same handler, already reports a missing workspace exactly that way — so the endpoint's 404 carries one uniform meaning whichever way the lookup fails.no_workspace_contains_path()returns the error rather than wrapping aResult, becauseApiErroris large enough that aResult<_, ApiError>helper tripsclippy::result_large_errunder CI's-D warnings.Compatibility
/containers/infois used by the VSCode extension. Its success path is unchanged; only the not-found path moves 500 → 404. Nothing can reasonably depend on the 500, and a client distinguishing "no workspace here" from "server broken" is the point.Testing
619 workspace tests pass;
cargo clippy --workspace --all-targets --exclude vibe-kanban-tauri -- -D warningsclean (CI's exact invocation).New coverage:
Ok(None), explicitly asserting it is not an error!status.is_server_error()