paperclipai/paperclip · error

Select a company to upload images

Error message

Select a company to upload images

What it means

The image-upload mutation in AgentDetail requires an active company selection because assets are uploaded to a company-scoped assets API endpoint. If the user has not selected a company (selectedCompanyId is null/undefined), the mutation throws this error instead of calling assetsApi.uploadImage. It is a guard against an impossible/ambiguous request rather than an API failure.

Source

Thrown at ui/src/pages/AgentDetail.production.tsx:2434

    },
    onError: () => setAwaitingRefresh(false),
  });

  const deleteFile = useMutation({
    mutationFn: (relativePath: string) => agentsApi.deleteInstructionsFile(agent.id, relativePath, companyId),
    onMutate: () => setAwaitingRefresh(true),
    onSuccess: (_, relativePath) => {
      queryClient.invalidateQueries({ queryKey: queryKeys.agents.instructionsBundle(agent.id) });
      queryClient.removeQueries({ queryKey: queryKeys.agents.instructionsFile(agent.id, relativePath) });
      queryClient.invalidateQueries({ queryKey: queryKeys.agents.detail(agent.id) });
      queryClient.invalidateQueries({ queryKey: queryKeys.agents.detail(agent.urlKey) });
    },
    onError: () => setAwaitingRefresh(false),
  });

  const uploadMarkdownImage = useMutation({
    mutationFn: async ({ file, namespace }: { file: File; namespace: string }) => {
      if (!selectedCompanyId) throw new Error("Select a company to upload images");
      return assetsApi.uploadImage(selectedCompanyId, file, namespace);
    },
  });

  useEffect(() => {
    if (!bundle) return;
    if (!bundleMatchesDraft) {
      if (selectedFile !== currentEntryFile) setSelectedFile(currentEntryFile);
      return;
    }
    const availablePaths = bundle.files.map((file) => file.path);
    if (availablePaths.length === 0) {
      if (selectedFile !== bundle.entryFile) setSelectedFile(bundle.entryFile);
      return;
    }
    if (!availablePaths.includes(selectedFile) && selectedFile !== currentEntryFile && !pendingFiles.includes(selectedFile)) {
      setSelectedFile(availablePaths.includes(bundle.entryFile) ? bundle.entryFile : availablePaths[0]!);
    }

View on GitHub (pinned to 01ad858492)

Solutions

  1. Select a company in the company picker before uploading/pasting images.
  2. Gate the upload affordance (paste/drop handler, toolbar button) on Boolean(selectedCompanyId) so it is disabled without a company.
  3. Ensure the company selection context is hydrated before rendering the editor.
  4. If the page is inherently company-scoped, redirect to company selection when selectedCompanyId is missing.

Example fix

// before
if (!selectedCompanyId) throw new Error("Select a company to upload images");
return assetsApi.uploadImage(selectedCompanyId, file, namespace);
// after (caller-side guard)
if (!selectedCompanyId) {
  toast.info("Select a company to upload images");
  return;
}
await uploadMarkdownImage.mutateAsync({ file, namespace });
Defensive patterns

Strategy: validation

Validate before calling

if (!selectedCompanyId) {
  toast.info("Select a company to upload images");
  return;
}

Type guard

const canUpload = (id: string | null | undefined): id is string => typeof id === "string" && id.length > 0;

Try / catch

try {
  await uploadMarkdownImage.mutateAsync({ file, namespace });
} catch (e) {
  if (e.message === "Select a company to upload images") toast.info(e.message);
  else toast.error("Image upload failed");
}

Prevention

When it happens

Trigger: Invoking uploadMarkdownImage.mutate({ file, namespace }) (e.g. pasting or dropping an image into the markdown editor) while no company is selected in the company selector.

Common situations: Landing on the agent detail page before the company context loads; the company selector was never set; a deep link that bypasses company selection; company data still fetching so the id is briefly null when the user pastes an image.

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/8b6ac07196fd2383. Report an issue: GitHub.