paperclipai/paperclip · error · Error

Invalid --by mode '${opts.by}'. Expected one of: auto, id, p

Error message

Invalid --by mode '${opts.by}'. Expected one of: auto, id, prefix.

What it means

Thrown at the start of the `company delete <selector>` action when `opts.by` (defaulted to "auto", trimmed+lowercased) is not one of auto/id/prefix. The --by flag controls how the selector is interpreted: auto (detect), id (UUID lookup), or prefix (issue prefix match).

Source

Thrown at cli/src/commands/client/company.ts:1933

    company
      .command("delete")
      .description("Delete a company by ID or shortname/prefix (destructive)")
      .argument("<selector>", "Company ID or issue prefix (for example PAP)")
      .option(
        "--by <mode>",
        "Selector mode: auto | id | prefix",
        "auto",
      )
      .option("--yes", "Required safety flag to confirm destructive action", false)
      .option(
        "--confirm <value>",
        "Required safety value: target company ID or shortname/prefix",
      )
      .action(async (selector: string, opts: CompanyDeleteOptions) => {
        try {
          const by = (opts.by ?? "auto").trim().toLowerCase() as CompanyDeleteSelectorMode;
          if (!["auto", "id", "prefix"].includes(by)) {
            throw new Error(`Invalid --by mode '${opts.by}'. Expected one of: auto, id, prefix.`);
          }

          const ctx = resolveCommandContext(opts);
          const normalizedSelector = normalizeSelector(selector);
          assertDeleteFlags(opts);

          let target: Company | null = null;
          const shouldTryIdLookup = by === "id" || (by === "auto" && isUuidLike(normalizedSelector));
          if (shouldTryIdLookup) {
            const byId = await ctx.api.get<Company>(apiPath`/api/companies/${normalizedSelector}`, { ignoreNotFound: true });
            if (byId) {
              target = byId;
            } else if (by === "id") {
              throw new Error(`No company found by ID '${normalizedSelector}'.`);
            }
          }

          if (!target && ctx.companyId) {

View on GitHub (pinned to 67001ec6eb)

Solutions

  1. Use `--by auto`, `--by id`, or `--by prefix`.
  2. Omit --by entirely to default to 'auto', which tries ID-then-prefix resolution.
  3. Run `paperclipai company delete --help` to confirm accepted values.

Example fix

# before
paperclipai company delete acme --by name --yes --confirm ACME
# after
paperclipai company delete acme --by prefix --yes --confirm ACME
Defensive patterns

Strategy: validation

Validate before calling

const BY_MODES = ["auto", "id", "prefix"] as const;
type ByMode = typeof BY_MODES[number];
function normalizeByMode(v: string | undefined): ByMode {
  const lower = (v ?? "auto").trim().toLowerCase();
  if (!BY_MODES.includes(lower as ByMode)) {
    throw new Error(`--by must be one of ${BY_MODES.join(", ")}`);
  }
  return lower as ByMode;
}

Type guard

function isByMode(v: unknown): v is "auto" | "id" | "prefix" {
  return typeof v === "string" && ["auto", "id", "prefix"].includes(v.toLowerCase());
}

Prevention

When it happens

Trigger: Passing `--by name`, `--by uuid`, `--by shortname`, or any token outside the three allowed; a typo like `--by pref`.

Common situations: Developer guesses 'name' or 'uuid' as the by-mode; copying a flag value from documentation that used different terms.

Related errors


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