paperclipai/paperclip · error · Error

Preview workflow definitions must run from master.

Error message

Preview workflow definitions must run from master.

What it means

The 'plan' and 'plan-migrator' subcommands of the preview-artifacts script are only allowed to run on the master branch. When invoked in a GitHub Actions workflow whose GITHUB_REF is not 'refs/heads/master', the script throws this error to prevent computing preview artifact plans from non-canonical branches.

Solutions

  1. Trigger the preview workflow from the master branch (push or workflow_dispatch on master).
  2. If testing locally, set GITHUB_REF=refs/heads/master when invoking the script.
  3. Adjust the GitHub Actions trigger/branch filter so the plan job only runs on master.
  4. For local development outside CI, invoke the internal planArtifacts logic directly rather than the CLI gate.

Example fix

// before (fails on a branch)
on: push
// after: restrict the plan job to master
on:
  push:
    branches: [master]
Defensive patterns

Strategy: validation

Validate before calling

if (process.env.GITHUB_REF !== 'refs/heads/master') throw new Error('plan must run from master; ref=' + process.env.GITHUB_REF);

Type guard

const isMasterRun = () => process.env.GITHUB_REF === 'refs/heads/master';

Try / catch

try {
  execSync('node scripts/preview-artifacts.mjs plan ...');
} catch (e) {
  if (String(e).includes('must run from master')) {
    console.error('Re-trigger the preview workflow on master.');
    process.exit(1);
  }
  throw e;
}

Prevention

When it happens

Trigger: Running `preview-artifacts.mjs plan <sha> <requestId>` (or plan-migrator) in a workflow triggered from a feature branch, pull request ref (e.g. refs/pull/123/merge), or tag so that process.env.GITHUB_REF differs from 'refs/heads/master'.

Common situations: Testing the preview workflow manually via workflow_dispatch on a branch; reusing the plan step in a fork or PR-triggered job; a workflow file with a wrong `runs-on` trigger branch configuration.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18). Data as JSON: /api/errors/eceb9c26cf471032. Report an issue: GitHub.

Appendix: source

Thrown at scripts/preview-artifacts.mjs:205

    const checks = await Promise.all([...pending].map(async (name) => ({ name, visible: await packageExists(name, sha, fetchImpl) })));
    for (const { name, visible } of checks) {
      if (visible) {
        pending.delete(name);
        console.log(`Visible ${name}@${versionFor(sha)}`);
      }
    }
    if (pending.size) await sleep(10_000);
  }
  if (pending.size) throw new Error(`npm accepted the preview but it is not yet visible: ${[...pending].join(", ")}. Retry reuses published packages.`);
}

if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
  const [command, ...args] = process.argv.slice(2);
  try {
    if (command === "plan" || command === "plan-migrator") {
      const [sha, requestId, migrator] = args;
      validateRequest(sha, requestId);
      if (process.env.GITHUB_REF !== "refs/heads/master") throw new Error("Preview workflow definitions must run from master.");
      const { image, packages } = await planArtifacts(sha, {
        image: command === "plan", migrator: command === "plan-migrator" || migrator === "true",
      });
      appendFileSync(process.env.GITHUB_OUTPUT, `image=${image}\npackages=${packages}\n`);
    } else if (command === "pack") packPreview(...args);
    else if (command === "publish") await publishPreview(...args);
    else if (command === "publish-image") await publishImage(...args);
    else if (command === "result") {
      const [sha, requestId] = args;
      validateRequest(sha, requestId);
      if (!await imageExists(sha)) throw new Error("Cloud image is still missing.");
      if (process.env.PREVIEW_MIGRATOR === "true" && !(await packageExists("@paperclipai/shared", sha) && await packageExists("@paperclipai/db", sha))) throw new Error("Preview packages are still missing.");
      mkdirSync("stack-deploy-result", { recursive: true });
      writeFileSync("stack-deploy-result/result.json", JSON.stringify({ version: 1, stage: "build", requestId, sha, status: "ready" }) + "\n");
    } else throw new Error("Expected plan, plan-migrator, pack, publish, publish-image, or result.");
  } catch (error) { console.error(error.message); process.exitCode = 1; }
}

View on GitHub (pinned to 3f1d897a7c)