paperclipai/paperclip · error · Error

/ / : required field needs placeholder

Error message

${app.slug}/${connectionMethod.key}/${connectionField.key}: required field needs placeholder

What it means

validateApp() requires every required connection field (across tenantFields, extensionFields, credentialFields) that is not a checkbox to carry a placeholder — the example text shown in the connection form. Required non-checkbox fields without placeholder text would render an empty hint in the UI, so the definition is rejected.

Solutions

  1. Add a placeholder string to the required field describing the expected input format (e.g. placeholder: "sk-live-...").
  2. When using the field() helper, pass the placeholder as the third argument instead of leaving it undefined.
  3. If no example text makes sense (e.g. a toggle), change the field type to "checkbox" or make it optional.

Example fix

// before
{ key: "accountSid", label: "Account SID", required: true, type: "text" }
// after
{ key: "accountSid", label: "Account SID", required: true, type: "text", placeholder: "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" }
Defensive patterns

Strategy: validation

Validate before calling

for (const m of app.methods) {
  for (const f of [...(m.tenantFields ?? []), ...(m.extensionFields ?? []), ...(m.credentialFields ?? [])]) {
    if (f.required && f.type !== 'checkbox' && !f.placeholder) throw new Error(`${m.key}/${f.key} needs a placeholder`);
  }
}

Type guard

const fieldOk = (f) => !f.required || f.type === 'checkbox' || (typeof f.placeholder === 'string' && f.placeholder.length > 0);

Prevention

When it happens

Trigger: A field object in tenantFields/extensionFields/credentialFields has required: true, type !== "checkbox", and placeholder missing/empty. Common with fields built inline as { key, label, required: true, type } without a placeholder property.

Common situations: Adding a new required tenant/credential field and forgetting the placeholder argument; the field() helper signature is (key, label, placeholder) so omitting the third argument yields undefined; a YAML/JSON-authored definition where placeholder was left blank for a required select/text field.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at scripts/ingest-app-definitions.mjs:1606

      );
    if (
      connectionMethod.auth === "oauth" &&
      connectionMethod.ownershipModes.length === 0
    )
      throw new Error(
        `${app.slug}/${connectionMethod.key}: oauth requires ownershipModes`,
      );
    for (const connectionField of [
      ...(connectionMethod.tenantFields ?? []),
      ...(connectionMethod.extensionFields ?? []),
      ...(connectionMethod.credentialFields ?? []),
    ])
      if (
        connectionField.required &&
        connectionField.type !== "checkbox" &&
        !connectionField.placeholder
      )
        throw new Error(
          `${app.slug}/${connectionMethod.key}/${connectionField.key}: required field needs placeholder`,
        );
  }
};
const captureFiles = definitionsOnly ? [] : fs
  .readdirSync(corpus)
  .filter((fileName) => fileName.endsWith(".md") && fileName !== "INDEX.md")
  .sort();
if (!definitionsOnly && captureFiles.length !== 99)
  throw new Error(`Expected 99 captures, found ${captureFiles.length}`);
const parsedCaptures = Object.fromEntries(
  captureFiles.map((fileName) => [
    path.basename(fileName, ".md"),
    parseCapture(fileName),
  ]),
);
const reviewReport = {
  schemaVersion: 1,

View on GitHub (pinned to 3f1d897a7c)