{"record":{"id":"0da580f16a88112d","repo":"siyuan-note/siyuan","slug":"invalid-card-cover-source-s","errorCode":null,"errorMessage":"invalid card cover source [%s]","messagePattern":"invalid card cover source \\[(.+?)\\]","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"kernel/model/attribute_view.go","lineNumber":1915,"sourceCode":"\nfunc (tx *Transaction) doSetAttrViewCardCoverPosition(operation *Operation) (ret *TxErr) {\n\tif err := setAttrViewCardCoverPosition(operation); nil != err {\n\t\treturn &TxErr{code: TxErrHandleAttributeView, id: operation.AvID, msg: err.Error()}\n\t}\n\treturn\n}\n\nfunc setAttrViewCardCoverPosition(operation *Operation) (err error) {\n\tdataJSON, err := json.Marshal(operation.Data)\n\tif nil != err {\n\t\treturn\n\t}\n\tvar data setAttrViewCardCoverPositionData\n\tif err = json.Unmarshal(dataJSON, &data); nil != err {\n\t\treturn\n\t}\n\tif !av.IsValidCardCoverSource(data.Source) {\n\t\treturn fmt.Errorf(\"invalid card cover source [%s]\", data.Source)\n\t}\n\tif nil != data.Position {\n\t\tif \"\" == data.Position.Image || 32*1024 < len(data.Position.Image) {\n\t\t\treturn errors.New(\"invalid card cover image\")\n\t\t}\n\t\tif math.IsNaN(data.Position.X) || math.IsInf(data.Position.X, 0) ||\n\t\t\tmath.IsNaN(data.Position.Y) || math.IsInf(data.Position.Y, 0) ||\n\t\t\tdata.Position.X < 0 || 100 < data.Position.X || data.Position.Y < 0 || 100 < data.Position.Y {\n\t\t\treturn fmt.Errorf(\"invalid card cover position [%v, %v]\", data.Position.X, data.Position.Y)\n\t\t}\n\t}\n\n\tattrView, err := av.ParseAttributeView(operation.AvID)\n\tif nil != err {\n\t\treturn\n\t}\n\tif nil == attrView.GetBlockValue(operation.RowID) {\n\t\treturn fmt.Errorf(\"attribute view item [%s] not found\", operation.RowID)","sourceCodeStart":1897,"sourceCodeEnd":1933,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/attribute_view.go#L1897-L1933","documentation":"Returned by setAttrViewCardCoverPosition (attribute_view.go:1915), dispatched through the transaction action \"setAttrViewCardCoverPosition\". After unmarshaling operation.Data into setAttrViewCardCoverPositionData, it validates data.Source via av.IsValidCardCoverSource. A valid source is either the literal \"content\" (CardCoverSourceContent) or the prefix \"asset:\" followed by a string matching ast.IsNodeIDPattern (a 14+-digit timestamp-style ID). Any other value fails.","triggerScenarios":"Frontend sends a cover position update whose source is empty, misspelled (e.g. \"contents\"), or an asset key without a valid node-ID suffix (e.g. \"asset:abc\"). The source must match how the cover was configured (CoverFrom + CoverFromAssetKeyID) and is re-checked against the view later (a mismatch yields \"card cover source does not match view\").","commonSituations":"Plugin constructs the source string by hand and gets the format wrong; UI sends an empty source when no cover is selected but still attaches a position object; keyID was deleted so the source became invalid.","solutions":["Build the source with av.CardCoverSource(coverFrom, assetKeyID): \"content\" for content images, \"asset:<keyID>\" for an asset field — and use the same keyID the view was configured with.","Send source = \"content\" exactly (lowercase, no prefix) for the content-image cover mode.","If the asset field was removed, clear the cover (CoverFromNone) instead of sending a stale asset source."],"exampleFix":"// before: hand-built source string\ntransaction({ op: \"setAttrViewCardCoverPosition\", data: { source: \"asset:\" + fieldId, position } })\n\n// after: derive source consistently with the view's cover config\nconst source = coverFrom === \"asset\" ? `asset:${view.coverFromAssetKeyID}` : \"content\"\ntransaction({ op: \"setAttrViewCardCoverPosition\", data: { source, position } })","handlingStrategy":"validation","validationCode":"// Build the source the same way the renderer does.\nconst source = coverFrom === 'asset' ? `asset:${view.coverFromAssetKeyID}` : 'content'\nif (!/^content$|^asset:\\d{14,}$/.test(source)) throw new Error('invalid card cover source')","typeGuard":"function isValidCardCoverSource(s: unknown): boolean {\n  if (typeof s !== 'string') return false\n  if (s === 'content') return true\n  return /^asset:\\d{14,}$/.test(s)\n}","tryCatchPattern":null,"preventionTips":["Derive the source from av.CardCoverSource(coverFrom, assetKeyID), not by hand.","Use exactly \"content\" (lowercase) for the content-image mode.","Clear the cover (CoverFromNone) instead of sending a stale asset source when the field is gone."],"tags":["attribute-view","av","gallery","kanban","card","cover","validation","transaction"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}