siyuan-note/siyuan · warning

invalid card aspect ratio [%v]

Error message

invalid card aspect ratio [%v]

What it means

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].

Source

Thrown at kernel/model/attribute_view.go:1197

	err = av.SaveAttributeView(attrView)
	return
}

func (tx *Transaction) doSetAttrViewCardAspectRatioValue(operation *Operation) (ret *TxErr) {
	if err := setAttrViewCardAspectRatioValue(operation); nil != err {
		return &TxErr{code: TxErrHandleAttributeView, id: operation.AvID, msg: err.Error()}
	}
	return
}

func setAttrViewCardAspectRatioValue(operation *Operation) (err error) {
	ratio, err := getAttrViewOperationNumber(operation)
	if nil != err {
		return
	}
	if math.IsNaN(ratio) || math.IsInf(ratio, 0) ||
		ratio < av.CardAspectRatioValueMin || av.CardAspectRatioValueMax < ratio {
		return fmt.Errorf("invalid card aspect ratio [%v]", ratio)
	}

	attrView, err := av.ParseAttributeView(operation.AvID)
	if err != nil {
		return
	}
	view, err := getAttrViewViewByBlockID(attrView, operation.BlockID)
	if err != nil {
		return
	}

	switch view.LayoutType {
	case av.LayoutTypeTable:
		return
	case av.LayoutTypeGallery:
		view.Gallery.CardAspectRatioValue = ratio
	case av.LayoutTypeKanban:
		view.Kanban.CardAspectRatioValue = ratio

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Clamp the custom ratio to the [0.25, 2.5] window before sending (the UI slider should enforce this).
  2. Guard against NaN/Inf when the ratio is derived from a division (check the divisor).
  3. If the value is a whole preset, prefer the preset action (setAttrViewCardAspectRatio) which also keeps CardAspectRatioValue in sync.

Example fix

// before: unguarded division can yield Infinity
transaction({ op: "setAttrViewCardAspectRatioValue", data: width / height })

// after: clamp into the valid window
const r = width / height
const ratio = Number.isFinite(r) ? Math.min(2.5, Math.max(0.25, r)) : 16/9
transaction({ op: "setAttrViewCardAspectRatioValue", data: ratio })
Defensive patterns

Strategy: validation

Validate before calling

// Clamp the custom ratio into [0.25, 2.5] and reject non-finite values.
if (!Number.isFinite(ratio)) throw new Error('ratio must be finite')
const safe = Math.min(2.5, Math.max(0.25, ratio))

Type guard

function isValidAspectRatioValue(v: unknown): v is number {
  return typeof v === 'number' && Number.isFinite(v) && v >= 0.25 && v <= 2.5
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/5220b43fa843fc2d. Report an issue: GitHub.