{"record":{"id":"567235538859fbce","repo":"paperclipai/paperclip","slug":"adapter-declares-unsupported-ui-parser-contract-ve","errorCode":null,"errorMessage":"Adapter declares unsupported UI parser contract version — skipping UI parser","messagePattern":"Adapter declares unsupported UI parser contract version — skipping UI parser","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"server/src/adapters/plugin-loader.ts","lineNumber":101,"sourceCode":"\nconst SUPPORTED_PARSER_CONTRACT = \"1\";\n\nfunction extractUiParserSource(\n  packageDir: string,\n  packageName: string,\n): string | undefined {\n  const pkgJsonPath = path.join(packageDir, \"package.json\");\n  const pkg = JSON.parse(fs.readFileSync(pkgJsonPath, \"utf-8\"));\n\n  if (!pkg.exports || typeof pkg.exports !== \"object\" || !pkg.exports[\"./ui-parser\"]) {\n    return undefined;\n  }\n\n  const contractVersion = pkg.paperclip?.adapterUiParser;\n  if (contractVersion) {\n    const major = contractVersion.split(\".\")[0];\n    if (major !== SUPPORTED_PARSER_CONTRACT) {\n      logger.warn(\n        { packageName, contractVersion, supported: `${SUPPORTED_PARSER_CONTRACT}.x` },\n        \"Adapter declares unsupported UI parser contract version — skipping UI parser\",\n      );\n      return undefined;\n    }\n  } else {\n    logger.info(\n      { packageName },\n      \"Adapter has ./ui-parser export but no paperclip.adapterUiParser version — loading anyway (future versions may require it)\",\n    );\n  }\n\n  const uiParserExp = pkg.exports[\"./ui-parser\"];\n  const uiParserFile = typeof uiParserExp === \"string\"\n    ? uiParserExp\n    : (uiParserExp.import ?? uiParserExp.default);\n  const uiParserPath = path.resolve(packageDir, uiParserFile);\n","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/paperclipai/paperclip/blob/a7e689b3c35347b529cb9f54c9b9a8575a3dcab6/server/src/adapters/plugin-loader.ts#L83-L119","documentation":"When loading a third-party adapter package, the plugin-loader reads package.json exports[\"./ui-parser\"] plus the pkg.paperclip.adapterUiParser contract version. If the declared major does not equal the server's SUPPORTED_PARSER_CONTRACT (currently \"1\"), the UI parser is skipped — the adapter itself still loads, but its UI parsing falls back to the default behavior.","triggerScenarios":"An adapter package declares paperclip.adapterUiParser like \"2.0\" (built against a newer contract) or \"0.x\" while the running paperclip-server supports major \"1\"; the loader logs this and returns undefined for the parser.","commonSituations":"Upgrading an adapter package without upgrading paperclip-server (or the reverse); community adapters lagging a contract bump; mixed lockfile versions in a monorepo.","solutions":["Align versions: upgrade paperclip-server (to get the new contract) or pin the adapter to a release built for contract major 1.","Inspect the adapter's package.json paperclip.adapterUiParser and compare against the server's supported major.","If you maintain the adapter, rebuild/republish against the contract version the target server supports.","Accept degraded UI parsing if the adapter's core functionality is unaffected."],"exampleFix":"// adapter package.json — before\n\"paperclip\": { \"adapterUiParser\": \"2.0\" }\n\n// after (targeting a contract-1 server)\n\"paperclip\": { \"adapterUiParser\": \"1.0\" }","handlingStrategy":"validation","validationCode":"const SUPPORTED_MAJOR = '1'; // keep in sync with the server's parser contract\nconst pkg = JSON.parse(fs.readFileSync(path.join(adapterDir, 'package.json'), 'utf-8'));\nconst declared = pkg.paperclip?.adapterUiParser;\nif (declared && declared.split('.')[0] !== SUPPORTED_MAJOR) {\n  throw new Error(`Adapter ${pkg.name} targets UI parser contract ${declared}; server supports ${SUPPORTED_MAJOR}.x`);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Upgrade paperclip-server and adapters in the same lockfile change.","When bumping the parser contract, grep all adapters for paperclip.adapterUiParser in the release checklist.","Smoke-test UI parsing (not just adapter load) after upgrades.","Publish adapters with the contract version field set so mismatches are detectable, not silent."],"tags":["adapter","contract-version","ui-parser","plugin-loader","compatibility"],"backgroundTag":"contract-version-mismatch","analyzedSha":"a7e689b3c35347b529cb9f54c9b9a8575a3dcab6","analyzedAt":"2026-08-18T22:49:45.177Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}