paperclipai/paperclip · error

Select a skill first.

Error message

Select a skill first.

What it means

The toggleStar mutation requires an active skill detail (activeDetail) to know which skill to star/unstar. If the detail pane has no selection, it throws this error instead of calling companySkillsApi.star/unstar. It is a client-side precondition guard against an ambiguous star toggle.

Source

Thrown at ui/src/pages/CompanySkills.production.tsx:4459

      setEditMode(false);
      pushToast({
        tone: "success",
        title: "Skill saved",
        body: result.path,
      });
    },
    onError: (error) => {
      pushToast({
        tone: "error",
        title: "Save failed",
        body: error instanceof Error ? error.message : "Failed to save skill file.",
      });
    },
  });

  const toggleStar = useMutation({
    mutationFn: () => {
      if (!activeDetail) throw new Error("Select a skill first.");
      return activeDetail.starredByCurrentActor
        ? companySkillsApi.unstar(selectedCompanyId!, activeDetail.id)
        : companySkillsApi.star(selectedCompanyId!, activeDetail.id);
    },
    onSuccess: async () => {
      if (!activeDetail) return;
      await Promise.all([
        queryClient.invalidateQueries({ queryKey: queryKeys.companySkills.list(selectedCompanyId!) }),
        queryClient.invalidateQueries({ queryKey: queryKeys.companySkills.detail(selectedCompanyId!, activeDetail.id) }),
      ]);
    },
    onError: (error) => {
      pushToast({
        tone: "error",
        title: "Star failed",
        body: error instanceof Error ? error.message : "Failed to update star.",
      });
    },

View on GitHub (pinned to 01ad858492)

Solutions

  1. Select a skill so the detail pane is populated, then toggle the star.
  2. Disable the star button when !activeDetail instead of allowing the mutation to run.
  3. Wire the toggle to an explicit skill id from the list row rather than shared activeDetail state.
  4. If activeDetail should always exist on this screen, investigate why detail selection was cleared (navigation, query error).

Example fix

// before
mutationFn: () => {
  if (!activeDetail) throw new Error("Select a skill first.");
  return activeDetail.starredByCurrentActor
    ? companySkillsApi.unstar(selectedCompanyId!, activeDetail.id)
    : companySkillsApi.star(selectedCompanyId!, activeDetail.id);
},
// after
mutationFn: () => {
  if (!activeDetail) throw new Error("Select a skill first.");
  return activeDetail.starredByCurrentActor
    ? companySkillsApi.unstar(selectedCompanyId!, activeDetail.id)
    : companySkillsApi.star(selectedCompanyId!, activeDetail.id);
},
// plus: <button disabled={!activeDetail} onClick={() => toggleStar.mutate()}>...</button>
Defensive patterns

Strategy: validation

Validate before calling

if (!activeDetail) {
  toast.info("Select a skill first.");
  return;
}

Type guard

const hasDetail = (d: typeof activeDetail): d is NonNullable<typeof activeDetail> => d != null;

Try / catch

try {
  await toggleStar.mutateAsync();
} catch (e) {
  if (e.message === "Select a skill first.") toast.info(e.message);
  else toast.error("Could not update star");
}

Prevention

When it happens

Trigger: Invoking toggleStar.mutate() while activeDetail is null/undefined — e.g. clicking the star control before a skill's detail has loaded or after the selection was cleared.

Common situations: Rendering the star toggle for a not-yet-loaded detail; a filter/search change cleared the active detail while the control stayed clickable; a race where the detail query is still fetching when the user clicks.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10). Data as JSON: /api/errors/9b2f90ec786164f6. Report an issue: GitHub.