{"record":{"id":"92bcd839cda3fba1","repo":"hcengineering/platform","slug":"no-default-content-adapter","errorCode":null,"errorMessage":"No default content adapter","messagePattern":"No default content adapter","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"foundations/server/packages/core/src/content.ts","lineNumber":49,"sourceCode":"\nexport async function createContentAdapter (\n  contentAdapters: Record<string, ContentTextAdapterConfiguration>,\n  defaultContentAdapter: string\n): Promise<ContentTextAdapter> {\n  const adapters = new Map<string, ContentTextAdapter>()\n  let defaultAdapter: ContentTextAdapter | undefined\n\n  for (const key in contentAdapters) {\n    const adapterConf = contentAdapters[key]\n    const adapter = await adapterConf.factory(adapterConf.url)\n\n    adapters.set(adapterConf.contentType, adapter)\n    if (key === defaultContentAdapter) {\n      defaultAdapter = adapter\n    }\n  }\n  if (defaultAdapter === undefined) {\n    throw new Error('No default content adapter')\n  }\n  return new ContentAdapter(adapters, defaultAdapter)\n}\n","sourceCodeStart":31,"sourceCodeEnd":53,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/foundations/server/packages/core/src/content.ts#L31-L53","documentation":"createContentAdapter builds a map of content adapters from configuration and selects the one whose contentType matches the configured default. If no registered adapter matches the defaultContentAdapter key, defaultAdapter stays undefined and this error is thrown instead of returning a ContentAdapter.","triggerScenarios":"Config lists adapters whose contentType values never equal the configured defaultContentAdapter key; or defaultContentAdapter names a contentType that has no adapter registered (typo, adapter omitted from config array).","commonSituations":"Typo in the default adapter name in workspace/server config; deploying with a custom content pipeline config where the default adapter section was removed; renaming a contentType in code without updating config.","solutions":["Check the config passed to startIndexer: ensure defaultContentAdapter exactly matches one adapter's contentType","Add or re-register an adapter for the configured default contentType","Fix the typo/case mismatch between the default name and adapter contentType keys"],"exampleFix":"// before\nadapters: [{ contentType: 'text/markdown' }], defaultContentAdapter: 'text/md'\n// after\nadapters: [{ contentType: 'text/markdown' }], defaultContentAdapter: 'text/markdown'","handlingStrategy":"validation","validationCode":"const conf = getConf()\nconst hasDefault = conf.adapters.some(a => a.contentType === conf.defaultContentAdapter)\nif (!hasDefault) throw new Error(`defaultContentAdapter '${conf.defaultContentAdapter}' has no matching adapter`)","typeGuard":"function hasDefaultAdapter(conf: { adapters: { contentType: string }[]; defaultContentAdapter: string }): boolean {\n  return conf.adapters.some(a => a.contentType === conf.defaultContentAdapter)\n}","tryCatchPattern":"try {\n  const adapter = createContentAdapter(...)\n} catch (err) {\n  if (err instanceof Error && err.message === 'No default content adapter') {\n    // fix config and retry / surface config error\n  } else throw err\n}","preventionTips":["Keep defaultContentAdapter and adapter contentType values in one shared constant","Validate adapter config at startup before indexing begins","Add a unit test asserting every config profile defines a matching default"],"tags":["configuration","content-adapter"],"backgroundTag":"missing-adapter-configuration","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}