BloopAI/vibe-kanban · error

Repository already attached to workspace

Error message

Repository already attached to workspace

What it means

This error is produced by map_workspace_manager_error when the workspace manager reports WorkspaceError::RepoAlreadyAttached. It means the repository being added is already associated with the target workspace, so the attach operation is rejected to preserve the one-repo-per-workspace-mapping invariant. It is a domain validation error surfaced as ContainerError::Other via anyhow.

Source

Thrown at crates/local-deployment/src/container.rs:149

        container
    }

    fn map_workspace_manager_error(err: WorkspaceError) -> ContainerError {
        match err {
            WorkspaceError::Database(err) => ContainerError::Sqlx(err),
            WorkspaceError::Worktree(err) => ContainerError::Worktree(err),
            WorkspaceError::GitService(err) => ContainerError::GitServiceError(err),
            WorkspaceError::Io(err) => ContainerError::Io(err),
            WorkspaceError::NoRepositories => {
                ContainerError::Other(anyhow!("No repositories provided"))
            }
            WorkspaceError::Repo(err) => ContainerError::Other(anyhow!(err)),
            WorkspaceError::WorkspaceNotFound => {
                ContainerError::Other(anyhow!("Workspace not found"))
            }
            WorkspaceError::RepoAlreadyAttached => {
                ContainerError::Other(anyhow!("Repository already attached to workspace"))
            }
            WorkspaceError::BranchNotFound { repo_name, branch } => ContainerError::Other(anyhow!(
                "Branch '{}' does not exist in repository '{}'",
                branch,
                repo_name
            )),
            WorkspaceError::PartialCreation(msg) => ContainerError::Other(anyhow!(msg)),
        }
    }

    async fn workspace_repo_inputs(
        &self,
        workspace_id: Uuid,
    ) -> Result<(Vec<Repo>, Vec<RepoWorkspaceInput>), ContainerError> {
        let workspace_repos =
            WorkspaceRepo::find_by_workspace_id(&self.db.pool, workspace_id).await?;
        if workspace_repos.is_empty() {
            return Err(ContainerError::Other(anyhow!(

View on GitHub (pinned to 4deb7eca8f)

Solutions

  1. Check existing workspace repos (WorkspaceRepo::find_by_workspace_id) before attaching and skip if already present.
  2. Treat the attach step as idempotent: catch this error and continue instead of failing the whole operation.
  3. If the repo is attached to the wrong workspace, detach/delete the existing WorkspaceRepo row first, then re-attach.
  4. Use a transaction/unique constraint so a retried create does not leave a half-created workspace.

Example fix

// before
manager.add_repo_to_workspace(ws_id, repo_id).await?;
// after
if !WorkspaceRepo::find_by_workspace_id(&pool, ws_id).await?
    .iter().any(|r| r.repo_id == repo_id) {
    manager.add_repo_to_workspace(ws_id, repo_id).await?;
}
Defensive patterns

Strategy: validation

Validate before calling

let existing = WorkspaceRepo::find_by_workspace_id(&pool, ws_id).await?;
if existing.iter().any(|r| r.repo_id == repo_id) {
    return Ok(()); // already attached, nothing to do
}

Try / catch

match container.add_repo_to_workspace(ws_id, repo_id).await {
    Err(e) if e.to_string().contains("already attached") => Ok(()), // idempotent
    other => other,
}

Prevention

When it happens

Trigger: Calling a workspace-creation or repo-attach API (e.g. container create / add repo to workspace) with a repo_id that already has a WorkspaceRepo row pointing at that workspace_id.

Common situations: Retrying a create request after a partial failure that already persisted the repo attachment; double-submitting a form from the UI; replaying an idempotency-unsafe create call; scripts that add repos to workspaces without checking existing mappings.

Related errors


AI-assisted analysis of BloopAI/vibe-kanban@4deb7eca8f (2026-08-29). Data as JSON: /api/errors/dc06a0533aa7c2e9. Report an issue: GitHub.