{"record":{"id":"4cfc669b17f51ce9","repo":"siyuan-note/siyuan","slug":"invalid-card-width-v","errorCode":null,"errorMessage":"invalid card width [%v]","messagePattern":"invalid card width \\[(.+?)\\]","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/attribute_view.go","lineNumber":1840,"sourceCode":"\terr = av.SaveAttributeView(attrView)\n\treturn\n}\n\nfunc (tx *Transaction) doSetAttrViewCardWidth(operation *Operation) (ret *TxErr) {\n\tif err := setAttrViewCardWidth(operation); nil != err {\n\t\treturn &TxErr{code: TxErrHandleAttributeView, id: operation.AvID, msg: err.Error()}\n\t}\n\treturn\n}\n\nfunc setAttrViewCardWidth(operation *Operation) (err error) {\n\tvalue, err := getAttrViewOperationNumber(operation)\n\tif nil != err {\n\t\treturn\n\t}\n\tif math.IsNaN(value) || math.IsInf(value, 0) || value != math.Trunc(value) ||\n\t\tvalue < av.CardWidthMin || av.CardWidthMax < value {\n\t\treturn fmt.Errorf(\"invalid card width [%v]\", value)\n\t}\n\twidth := int(value)\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.CardWidth = width\n\tcase av.LayoutTypeKanban:","sourceCodeStart":1822,"sourceCodeEnd":1858,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/attribute_view.go#L1822-L1858","documentation":"setAttrViewCardWidth validates the width number is finite, an integer, and within [av.CardWidthMin, av.CardWidthMax]; NaN, Infinity, fractions, and out-of-range values are rejected before the attribute view is parsed. Card width is a bounded integer setting, not an arbitrary number.","triggerScenarios":"Sending a setAttrViewCardWidth operation with a float (e.g. from getBoundingClientRect), NaN/Infinity from a bad computation, or a width below CardWidthMin / above CardWidthMax.","commonSituations":"Sub-pixel measurements passed unrounded; division by zero in a ratio-derived width; plugin constants predating the introduction of min/max clamps; manual API calls with percent values instead of the expected integer.","solutions":["Clamp the width to av.CardWidthMin..av.CardWidthMax and Math.round it before enqueueing the operation.","Guard the computation with Number.isFinite and reject non-numeric input early.","Check the current kernel constants for the valid range if the call previously worked."],"exampleFix":"// before\nsetCardWidth(avID, rect.width); // 213.33333\n// after\nconst w = Math.round(rect.width);\nif (Number.isFinite(w) && w >= CardWidthMin && w <= CardWidthMax) setCardWidth(avID, w);","handlingStrategy":"validation","validationCode":"const n = Number(value);\nif (!Number.isFinite(n) || !Number.isInteger(n) || n < CardWidthMin || n > CardWidthMax) throw new RangeError('card width out of range');","typeGuard":"const isValidCardWidth = (v: unknown): v is number => typeof v === 'number' && Number.isFinite(v) && Number.isInteger(v) && v >= CardWidthMin && v <= CardWidthMax;","tryCatchPattern":"try { await setCardWidth(avID, value); } catch (e) { if (String(e).includes('invalid card width')) { await setCardWidth(avID, clamp(Math.round(value), CardWidthMin, CardWidthMax)); } else throw e; }","preventionTips":["Math.round DOM measurements before sending","Clamp against CardWidthMin/Max at the UI layer","Reject NaN/Infinity from ratio or division-based computations early"],"tags":["attribute-view","validation","value-out-of-range"],"backgroundTag":"value-out-of-range","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}