{"record":{"id":"1f356ce4f7687d95","repo":"hcengineering/platform","slug":"no-info-for-mark-mark-type","errorCode":null,"errorMessage":"No info for mark ${mark.type}","messagePattern":"No info for mark (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"foundations/core/packages/text-markdown/src/serializer.ts","lineNumber":875,"sourceCode":"    return wrap[0] + str + wrap[1]\n  }\n\n  // :: (string, number) → string\n  // Repeat the given string `n` times.\n  repeat (str: string, n: number): string {\n    let out = ''\n    for (let i = 0; i < n; i++) out += str\n    return out\n  }\n\n  // : (Mark, bool, string?) → string\n  // Get the markdown string for a given opening or closing mark.\n  markString (mark: MarkupMark, open: boolean, parent: MarkupNode, index: number): string {\n    let value = mark.attrs?.marker\n    if (value === undefined) {\n      const info = this.marks[mark.type]\n      if (info == null) {\n        throw new Error(`No info for mark ${mark.type}`)\n      }\n      value = open ? info.open : info.close\n    }\n    return typeof value === 'string' ? value : (value(this, mark, parent, index) ?? '')\n  }\n}\n\nfunction makeQuery (obj: Record<string, string | number | boolean | null | undefined>): string {\n  return Object.keys(obj)\n    .filter((it) => it[1] != null)\n    .map(function (k) {\n      return encodeURIComponent(k) + '=' + encodeURIComponent(obj[k] as string | number | boolean)\n    })\n    .join('&')\n}\n","sourceCodeStart":857,"sourceCodeEnd":891,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/foundations/core/packages/text-markdown/src/serializer.ts#L857-L891","documentation":"markString() resolves the open/close Markdown syntax for a mark from this.marks. When a mark has no explicit attrs.marker and no registered mark info, the serializer does not know how to translate it and throws. This guards against emitting Markdown with broken/missing emphasis formatting.","triggerScenarios":"Serializing a document containing a mark type (e.g. a custom annotation or link variant) that is not registered in the Markdown state's marks table and carries no marker attribute.","commonSituations":"Custom marks added by extensions, marks from pasted rich text, schema changes adding new mark types without Markdown serializer support.","solutions":["Register the mark in the serializer's marks table with open/close strings or functions","Set an attrs.marker on the mark so markString can use it directly","Strip unsupported marks from the document before serialization"],"exampleFix":"// before\nmarks: {} // 'highlight' mark missing\n// after\nmarks: { highlight: { open: '==', close: '==' } }","handlingStrategy":"validation","validationCode":"for (const m of node.marks ?? []) {\n  if (!state.marks[m.type] && m.attrs?.marker === undefined) {\n    throw new Error(`mark ${m.type} has no markdown serialization`)\n  }\n}","typeGuard":"function hasMarkInfo(state: { marks: Record<string, unknown> }, mark: { type: string; attrs?: { marker?: string } }): boolean {\n  return mark.attrs?.marker !== undefined || state.marks[mark.type] != null\n}","tryCatchPattern":"try {\n  md = state.markString(mark, open, parent, index)\n} catch (e) {\n  if (e.message.startsWith('No info for mark')) {\n    return '' // or strip the mark\n  }\n  throw e\n}","preventionTips":["Register every mark type in your schema with the Markdown serializer","Prefer explicit attrs.marker for simple string marks","Test round-trip markdown conversion for all marks"],"tags":["markdown","serialization","marks"],"backgroundTag":"markdown-unsupported-mark-type","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}