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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions