Skip to content

Bug: prepare_workspace defaults to "fork" remote when no fork exists, causing infinite retry loop #181

Description

@danchild

Summary

prepare_workspace() unconditionally defaults remote="fork", causing git fetch fork to fail when called during initial implementation before any PR/fork has been created. The failure cascades into a ValueError and an infinite retry loop.

Observed Behavior

2026-07-17 13:16:46,681 - forge.workflow.nodes.implementation - ERROR - Unable to prepare implementation workspace for AISOS-2234: Cannot recreate workspace for AISOS-2234: missing branch_name, current_repo, fork_owner, or fork_repo in state
2026-07-17 13:16:46,684 - forge.workspace.git_ops - INFO - Syncing with fork/forge/aisos-2234 before implementing changes
2026-07-17 13:16:46,726 - forge.workflow.nodes.workspace_setup - WARNING - Workspace sync failed for AISOS-2234; recreating workspace from fork: Git command failed: git fetch fork
fatal: 'fork' does not appear to be a git repository

The workflow retries indefinitely, hitting the same error each time.

Root Cause

prepare_workspace() in src/forge/workflow/nodes/workspace_setup.py:62 has remote: str = "fork" as a default parameter. When the implementation node calls it during initial implementation (before any PR/fork has been created), fork_owner and fork_repo are empty strings in state.

The failure sequence:

  1. prepare_workspace() finds the workspace path exists on disk (line 94), taking the "sync existing workspace" path
  2. Calls git.pull_rebase(remote="fork") (line 103), which runs git fetch fork (git_ops.py:133)
  3. No "fork" remote existsadd_fork_remote() was never called because there is no fork yet
  4. git fetch fork fails → exception handler (line 104-117) falls through to _recreate_workspace_from_fork()
  5. _recreate_workspace_from_fork() checks fork_owner/fork_repo (line 35) — both are empty strings
  6. Raises ValueError: "Cannot recreate workspace... missing branch_name, current_repo, fork_owner, or fork_repo in state"
  7. Implementation node catches this, sets last_error, workflow retries → infinite loop

Correct Pattern Already Exists

setup_workspace() (lines 253-268 in the same file) handles this correctly:

fork_owner = state.get("fork_owner", "")
fork_repo_name = state.get("fork_repo", "")

if fork_owner and fork_repo_name:
    git.add_fork_remote(fork_owner, fork_repo_name)
    # ... use fork remote
else:
    git.create_branch(default_branch)  # use origin

prepare_workspace() does not replicate this guard.

Proposed Fix

prepare_workspace() should:

  1. Check whether fork_owner/fork_repo are populated in state
  2. When populated: call add_fork_remote() to ensure the remote exists, then sync with "fork"
  3. When empty: sync with "origin" instead of "fork"

This aligns prepare_workspace() with the pattern already established in setup_workspace().

Affected Files

  • src/forge/workflow/nodes/workspace_setup.pyprepare_workspace() (line 61)
  • src/forge/workspace/git_ops.pypull_rebase() (line 121, default remote="fork")

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions