paperclipai/paperclip · warning

Failed to seed CEO instructions:

Error message

Failed to seed CEO instructions:

What it means

Logged from the OnboardingWizard's first-agent setup: after agentsApi.hire() and approval succeed, the wizard fetches the CEO instructions bundle (agentsApi.instructionsBundle) and saves a seeded instructions file (agentsApi.saveInstructionsFile). If either API call rejects, the catch logs this warning and deliberately continues to step 5 — per the in-code comment, the failure is non-fatal because the hired agent can still run with adapter defaults.

Solutions

  1. Open browser devtools Network tab, find the failing /api/.../agents/{id}/instructions request and read the HTTP status — that is the real error (the warn only wraps it).
  2. Confirm the API is reachable: curl http://localhost:3100/api/health.
  3. If 401/403: log in again and restart onboarding.
  4. If the agent was created despite the warning: seed the CEO instructions manually from the agent's instructions page in the board UI.
  5. Check server logs for the 5xx root cause (workspace path, permissions) if the status is 500.

Example fix

// before
try {
  const bundle = await agentsApi.instructionsBundle(agent.id, createdCompanyId);
  await agentsApi.saveInstructionsFile(agent.id, { path: bundle.entryFile, content }, createdCompanyId);
} catch (err) {
  console.warn("Failed to seed CEO instructions:", err);
}

// after — same non-fatal contract, but the user is told instead of only the console
try {
  const bundle = await agentsApi.instructionsBundle(agent.id, createdCompanyId);
  await agentsApi.saveInstructionsFile(agent.id, { path: bundle.entryFile, content }, createdCompanyId);
} catch (err) {
  console.warn("Failed to seed CEO instructions:", err);
  setSeedInstructionsNotice("Agent created, but its instruction file could not be seeded. Edit it from the agent page.");
}
Defensive patterns

Strategy: try-catch

Validate before calling

const health = await fetch(`${apiBase}/api/health`);
if (!health.ok) throw new Error(`API unreachable (${health.status}) — fix connectivity before onboarding`);

Type guard

const isApiError = (e: unknown): e is { status?: number; message: string } =>
  typeof e === "object" && e !== null && "message" in e;

Try / catch

try {
  const bundle = await agentsApi.instructionsBundle(agent.id, companyId);
  await agentsApi.saveInstructionsFile(agent.id, { path: bundle.entryFile, content }, companyId);
} catch (err) {
  // Non-fatal by design: the agent exists. Log, optionally notify, continue the wizard.
  console.warn("Failed to seed CEO instructions:", err instanceof Error ? err.message : err);
}

Prevention

When it happens

Trigger: Running the onboarding wizard, completing agent hire, then the GET instructions-bundle or POST save-instructions-file request failing: API server restart mid-wizard, 401 from an expired session, 404 for a just-deleted agent/company, or a 5xx when the server cannot write the instructions file to the workspace.

Common situations: Dev server restarted while the wizard was open; auth token expired during a long wizard session; company context switched (stillTheSameCompany race); server-side filesystem/permission error writing the agent instructions file.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at ui/src/components/OnboardingWizard.tsx:1643

    reset();
    closeOnboarding();
    // On the /onboarding route the wizard is also kept open by the route
    // itself, so closing the dialog must mark the route dismissed — otherwise
    // effectiveOnboardingOpen stays true and the wizard re-renders instead of
    // handing off to the launcher card (PAP-52).
    setRouteDismissed(true);
  }

  /**
   * Whether the company an async handler started for is still the one in hand.
   *
   * A route change can switch companies while a request is in flight, and the
   * switch clears the created resource ids so the new company starts clean. A
   * write that lands afterwards would put them back, and hand that company the
   * previous one's goal, project, issue or agent — which is exactly what the
   * clearing exists to prevent.
   *
   * Every async write below asks this before it attributes anything. It never
   * cancels the server work, which is done and correct either way; it declines
   * only to record it against a company it does not belong to.
   */
  function stillTheSameCompany(companyIdAtStart: string | null) {
    return createdCompanyIdRef.current === companyIdAtStart;
  }

  /**
   * Whether a just-created company can still be committed to this wizard.
   *
   * Company-list refreshes can make the surrounding app adopt the POST result
   * before the continuation runs. That is the same successful transition, not
   * a takeover. A different id still means navigation moved the wizard to a
   * different organization while the request was in flight.
   */
  function canCommitCreatedCompany(
    companyIdAtStart: string | null,
    returnedCompanyId: string,

View on GitHub (pinned to 3f1d897a7c)