paperclipai/paperclip · error · Error

No update status returned for skill ${skill.key}.

Error message

No update status returned for skill ${skill.key}.

What it means

Thrown by checkCompanySkills() when GET /api/companies/{companyId}/skills/{skillId}/update-status returns null/undefined for an installed skill. The CLI expects a CompanySkillUpdateStatus object; a null body is treated as a contract violation rather than silently skipping the row.

Source

Thrown at cli/src/commands/client/skills.ts:649

  ctx: ResolvedClientContext,
  reference: string,
): Promise<CompanySkillReferenceTarget> {
  return resolveCompanySkillReference(await listCompanySkills(ctx), reference);
}

async function checkCompanySkills(
  ctx: ResolvedClientContext,
  skillRef: string | undefined,
): Promise<CompanySkillCheckRow[]> {
  const skills = await listCompanySkills(ctx);
  const selected = skillRef ? [resolveCompanySkillReference(skills, skillRef)] : skills;
  const rows: CompanySkillCheckRow[] = [];
  for (const skill of selected) {
    const status = await ctx.api.get<CompanySkillUpdateStatus>(
      `/api/companies/${ctx.companyId}/skills/${encodeURIComponent(skill.id)}/update-status`,
    );
    if (!status) {
      throw new Error(`No update status returned for skill ${skill.key}.`);
    }
    rows.push({ skill: toSkillReferenceTarget(skill), status });
  }
  return rows;
}

async function updateOneCompanySkill(
  ctx: ResolvedClientContext,
  skillRef: string,
  opts: SkillUpdateOptions = {},
): Promise<CompanySkillUpdateRow> {
  const skill = await resolveCompanySkill(ctx, skillRef);
  const updated = await ctx.api.post<CompanySkill>(
    `/api/companies/${ctx.companyId}/skills/${encodeURIComponent(skill.id)}/install-update`,
    { force: opts.force || undefined },
  );
  return {
    skillRef,

View on GitHub (pinned to 67001ec6eb)

Solutions

  1. Confirm CLI and server versions match (`paperclipai --version`, server /api/health).
  2. Retry `skills check` after refreshing the company context.
  3. If persistent, inspect the raw response with `curl /api/companies/{id}/skills/{sid}/update-status` to see whether the server or transport drops the body.

Example fix

# before
paperclipai skills check my-skill
# diagnose
curl -sS "$API/api/companies/$CID/skills/$SID/update-status" -H "authorization: Bearer $TOKEN" | jq .
Defensive patterns

Strategy: try-catch

Type guard

function isUpdateStatus(v: unknown): v is CompanySkillUpdateStatus {
  return v != null && typeof v === "object";
}

Try / catch

try {
  await run(["skills", "check", ref]);
} catch (err) {
  if (err instanceof Error && /No update status returned/.test(err.message)) {
    console.error("Server returned no status. Check CLI/server version alignment.");
    process.exit(2);
  }
  throw err;
}

Prevention

When it happens

Trigger: `paperclipai skills check [skillRef]` (or the per-skill update-status fetch) where the server returns an empty 2xx response, the route is missing in the deployed API version, or a proxy strips the body.

Common situations: Version skew between an older/newer CLI and server, a misbehaving gateway that returns 200 with no body, or the skill id resolving to a row the server no longer recognizes mid-flight.

Related errors


AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12). Data as JSON: /api/errors/fdc73fc3f4a8b428. Report an issue: GitHub.