mastra-ai/mastra · error · MaterializeError

pull-failed

pull-failed

Error message

Failed to set git remote: ${setUrl.stderr}

What it means

On re-open of an already-materialized repo, materializeRepo refreshes the origin remote to the authenticated token URL via `git remote set-url origin <authUrl>`; a non-zero exit throws this MaterializeError with code pull-failed, embedding git's stderr. The re-open pull flow can't authenticate without resetting the remote URL, so it aborts.

Source

Thrown at mastracode/factory/src/integrations/github/sandbox.ts:321

              sandbox,
              `mkdir -p ${shellQuote(workdir)} && find ${shellQuote(workdir)} -mindepth 1 -maxdepth 1 -exec rm -rf -- {} +`,
            );
          },
        },
      );
      if (clone.exitCode !== 0) {
        // git can fail after creating the checkout ("Clone succeeded, but
        // checkout failed") with the tokenized origin persisted — probe the
        // disk instead of assuming the failed clone left nothing behind.
        tokenInRemote = await hasGitDir(sandbox, workdir);
        throw classifyGitFailure(clone, 'clone-failed');
      }
      tokenInRemote = true;
    } else {
      // 2b. Re-open: refresh remote to the token URL and fast-forward pull.
      const setUrl = await sh(sandbox, `git -C ${shellQuote(workdir)} remote set-url origin ${shellQuote(authUrl)}`);
      if (setUrl.exitCode !== 0) {
        throw new MaterializeError(`Failed to set git remote: ${setUrl.stderr}`, 'pull-failed');
      }
      tokenInRemote = true;
      const pull = await gitTransfer(sandbox, `git -C ${shellQuote(workdir)} pull --ff-only`, {
        phase: 'repository pull',
      });
      if (pull.exitCode !== 0) {
        if (!isBenignNonFastForward(pull)) {
          throw classifyGitFailure(pull, 'pull-failed');
        }
        // The workdir was left on a session's working branch that can't be
        // fast-forwarded (diverged from upstream, no upstream, or detached
        // HEAD), or its configured upstream ref was deleted after merge.
        // That checkout still holds usable work — never rebase or reset it
        // here. Leave it as-is and let the session reconcile with the remote
        // itself.
      }
    }
  } catch (primary) {

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Inspect the embedded stderr in the message for the underlying git cause.
  2. Reset the binding so the workdir is re-cloned (delete the sandbox workdir or the materialization row) and retry.
  3. Free sandbox disk space or fix filesystem permissions if stderr indicates ENOSPC/EACCES.
  4. Re-run materialization with a fresh sandbox instance.
Defensive patterns

Strategy: retry

Validate before calling

const check = await sh(sandbox, `git -C ${shellQuote(workdir)} rev-parse --git-dir`);
if (check.exitCode !== 0) {
  // not a git repo anymore — clear the binding so the flow re-clones instead of pulling
  await resetMaterialization(storage, sandboxRow);
}

Try / catch

try {
  await materializeRepo(options);
} catch (err) {
  if (err instanceof MaterializeError && err.code === 'pull-failed' && err.message.startsWith('Failed to set git remote')) {
    await resetMaterialization(storage, sandboxRow); // drop row/workdir
    return materializeRepo(options); // fresh clone path
  }
  throw err;
}

Prevention

When it happens

Trigger: `git remote set-url` failing inside the sandbox because the workdir is no longer a git repository (wiped/partial .git), the filesystem is read-only or full, origin was deleted, or the sandbox process is denied executing git.

Common situations: A sandbox disk restored from a checkpoint where .git was lost while files remained; sandbox volume full; workdir manually modified by a user's session commands.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/361842ddcd90f3de. Report an issue: GitHub.