{"record":{"id":"5220b43fa843fc2d","repo":"siyuan-note/siyuan","slug":"invalid-card-aspect-ratio-v","errorCode":null,"errorMessage":"invalid card aspect ratio [%v]","messagePattern":"invalid card aspect ratio \\[(.+?)\\]","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"kernel/model/attribute_view.go","lineNumber":1197,"sourceCode":"\terr = av.SaveAttributeView(attrView)\n\treturn\n}\n\nfunc (tx *Transaction) doSetAttrViewCardAspectRatioValue(operation *Operation) (ret *TxErr) {\n\tif err := setAttrViewCardAspectRatioValue(operation); nil != err {\n\t\treturn &TxErr{code: TxErrHandleAttributeView, id: operation.AvID, msg: err.Error()}\n\t}\n\treturn\n}\n\nfunc setAttrViewCardAspectRatioValue(operation *Operation) (err error) {\n\tratio, err := getAttrViewOperationNumber(operation)\n\tif nil != err {\n\t\treturn\n\t}\n\tif math.IsNaN(ratio) || math.IsInf(ratio, 0) ||\n\t\tratio < av.CardAspectRatioValueMin || av.CardAspectRatioValueMax < ratio {\n\t\treturn fmt.Errorf(\"invalid card aspect ratio [%v]\", ratio)\n\t}\n\n\tattrView, err := av.ParseAttributeView(operation.AvID)\n\tif err != nil {\n\t\treturn\n\t}\n\tview, err := getAttrViewViewByBlockID(attrView, operation.BlockID)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tswitch view.LayoutType {\n\tcase av.LayoutTypeTable:\n\t\treturn\n\tcase av.LayoutTypeGallery:\n\t\tview.Gallery.CardAspectRatioValue = ratio\n\tcase av.LayoutTypeKanban:\n\t\tview.Kanban.CardAspectRatioValue = ratio","sourceCodeStart":1179,"sourceCodeEnd":1215,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/attribute_view.go#L1179-L1215","documentation":"Returned by setAttrViewCardAspectRatioValue (attribute_view.go:1197), dispatched through the transaction action \"setAttrViewCardAspectRatioValue\". Unlike the preset action (error 426), this accepts a free-form width/height ratio. The value must be finite (not NaN/Inf) and within [av.CardAspectRatioValueMin=0.25, av.CardAspectRatioValueMax=2.5].","triggerScenarios":"Frontend sends a setAttrViewCardAspectRatioValue transaction whose data is NaN/Inf or outside 0.25–2.5. This is the custom-ratio path used when the user types a free value rather than picking a preset.","commonSituations":"User types 0 or a negative number in a custom ratio field; plugin computes ratio/0 producing Inf or 0/0 producing NaN; value persisted from an older build with different bounds replayed after the bounds tightened.","solutions":["Clamp the custom ratio to the [0.25, 2.5] window before sending (the UI slider should enforce this).","Guard against NaN/Inf when the ratio is derived from a division (check the divisor).","If the value is a whole preset, prefer the preset action (setAttrViewCardAspectRatio) which also keeps CardAspectRatioValue in sync."],"exampleFix":"// before: unguarded division can yield Infinity\ntransaction({ op: \"setAttrViewCardAspectRatioValue\", data: width / height })\n\n// after: clamp into the valid window\nconst r = width / height\nconst ratio = Number.isFinite(r) ? Math.min(2.5, Math.max(0.25, r)) : 16/9\ntransaction({ op: \"setAttrViewCardAspectRatioValue\", data: ratio })","handlingStrategy":"validation","validationCode":"// Clamp the custom ratio into [0.25, 2.5] and reject non-finite values.\nif (!Number.isFinite(ratio)) throw new Error('ratio must be finite')\nconst safe = Math.min(2.5, Math.max(0.25, ratio))","typeGuard":"function isValidAspectRatioValue(v: unknown): v is number {\n  return typeof v === 'number' && Number.isFinite(v) && v >= 0.25 && v <= 2.5\n}","tryCatchPattern":null,"preventionTips":["Clamp the slider/text input to 0.25–2.5 on the client.","Guard against division by zero when computing width/height.","Prefer the preset action for standard ratios to keep CardAspectRatioValue in sync."],"tags":["attribute-view","av","gallery","kanban","card","validation","transaction"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}