{"record":{"id":"c8423c950ba9e764","repo":"paperclipai/paperclip","slug":"app-slug-connectionmethod-key-connectionfield-key-required","errorCode":null,"errorMessage":"${app.slug}/${connectionMethod.key}/${connectionField.key}: required field needs placeholder","messagePattern":"(.+?)/(.+?)/(.+?): required field needs placeholder","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/ingest-app-definitions.mjs","lineNumber":1606,"sourceCode":"      );\n    if (\n      connectionMethod.auth === \"oauth\" &&\n      connectionMethod.ownershipModes.length === 0\n    )\n      throw new Error(\n        `${app.slug}/${connectionMethod.key}: oauth requires ownershipModes`,\n      );\n    for (const connectionField of [\n      ...(connectionMethod.tenantFields ?? []),\n      ...(connectionMethod.extensionFields ?? []),\n      ...(connectionMethod.credentialFields ?? []),\n    ])\n      if (\n        connectionField.required &&\n        connectionField.type !== \"checkbox\" &&\n        !connectionField.placeholder\n      )\n        throw new Error(\n          `${app.slug}/${connectionMethod.key}/${connectionField.key}: required field needs placeholder`,\n        );\n  }\n};\nconst captureFiles = definitionsOnly ? [] : fs\n  .readdirSync(corpus)\n  .filter((fileName) => fileName.endsWith(\".md\") && fileName !== \"INDEX.md\")\n  .sort();\nif (!definitionsOnly && captureFiles.length !== 99)\n  throw new Error(`Expected 99 captures, found ${captureFiles.length}`);\nconst parsedCaptures = Object.fromEntries(\n  captureFiles.map((fileName) => [\n    path.basename(fileName, \".md\"),\n    parseCapture(fileName),\n  ]),\n);\nconst reviewReport = {\n  schemaVersion: 1,","sourceCodeStart":1588,"sourceCodeEnd":1624,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/scripts/ingest-app-definitions.mjs#L1588-L1624","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Add a placeholder string to the required field describing the expected input format (e.g. placeholder: \"sk-live-...\").","When using the field() helper, pass the placeholder as the third argument instead of leaving it undefined.","If no example text makes sense (e.g. a toggle), change the field type to \"checkbox\" or make it optional."],"exampleFix":"// before\n{ key: \"accountSid\", label: \"Account SID\", required: true, type: \"text\" }\n// after\n{ key: \"accountSid\", label: \"Account SID\", required: true, type: \"text\", placeholder: \"ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\" }","handlingStrategy":"validation","validationCode":"for (const m of app.methods) {\n  for (const f of [...(m.tenantFields ?? []), ...(m.extensionFields ?? []), ...(m.credentialFields ?? [])]) {\n    if (f.required && f.type !== 'checkbox' && !f.placeholder) throw new Error(`${m.key}/${f.key} needs a placeholder`);\n  }\n}","typeGuard":"const fieldOk = (f) => !f.required || f.type === 'checkbox' || (typeof f.placeholder === 'string' && f.placeholder.length > 0);","tryCatchPattern":null,"preventionTips":["Always pass the placeholder argument to the field() helper; treat it as required in code review.","Include a realistic format example in each placeholder (e.g. key prefixes, ID shapes).","Run the ingest script before committing new fields — it catches this immediately."],"tags":["validation","form-fields","ux","ingest"],"backgroundTag":"empty-required-field","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}