siyuan-note/siyuan · warning
invalid card cover image
Error message
invalid card cover image
What it means
Returned by setAttrViewCardCoverPosition (attribute_view.go:1919) when data.Position is non-nil but its Image field is empty or exceeds 32*1024 bytes (32 KiB). The Image field holds the cover image payload (a data URL / base64 used as a cache key for the position). The guard runs only when a position object is present; sending position = null is valid and clears the stored position.
Source
Thrown at kernel/model/attribute_view.go:1919
}
return
}
func setAttrViewCardCoverPosition(operation *Operation) (err error) {
dataJSON, err := json.Marshal(operation.Data)
if nil != err {
return
}
var data setAttrViewCardCoverPositionData
if err = json.Unmarshal(dataJSON, &data); nil != err {
return
}
if !av.IsValidCardCoverSource(data.Source) {
return fmt.Errorf("invalid card cover source [%s]", data.Source)
}
if nil != data.Position {
if "" == data.Position.Image || 32*1024 < len(data.Position.Image) {
return errors.New("invalid card cover image")
}
if math.IsNaN(data.Position.X) || math.IsInf(data.Position.X, 0) ||
math.IsNaN(data.Position.Y) || math.IsInf(data.Position.Y, 0) ||
data.Position.X < 0 || 100 < data.Position.X || data.Position.Y < 0 || 100 < data.Position.Y {
return fmt.Errorf("invalid card cover position [%v, %v]", data.Position.X, data.Position.Y)
}
}
attrView, err := av.ParseAttributeView(operation.AvID)
if nil != err {
return
}
if nil == attrView.GetBlockValue(operation.RowID) {
return fmt.Errorf("attribute view item [%s] not found", operation.RowID)
}
view, err := getAttrViewViewByBlockID(attrView, operation.BlockID)
if nil != err {
returnView on GitHub (pinned to 251596fc0d)
Solutions
- Send a short, stable image identifier (e.g. the asset URL/hash, not the full base64) under 32 KiB in position.image, or omit the position object to clear it.
- If you only want to set X/Y focus, pass the same image reference the renderer uses as the cache key, trimmed to well under 32 KiB.
- Send position = null when clearing the focal point rather than an object with an empty Image.
Example fix
// before: embedding the full base64 cover
transaction({ op: "setAttrViewCardCoverPosition", data: { source, position: { image: fullBase64, x, y } } })
// after: use a short cache key (the asset URL/hash)
transaction({ op: "setAttrViewCardCoverPosition", data: { source, position: { image: coverURL, x, y } } }) Defensive patterns
Strategy: validation
Validate before calling
// image must be a short cache key, not full base64; cap at 32 KiB.
if (position && (position.image === '' || position.image.length > 32 * 1024)) {
throw new Error('invalid card cover image')
} Type guard
function isValidCoverImage(position: unknown): boolean {
if (position == null) return true // null clears the position
if (typeof position !== 'object') return false
const img = (position as any).image
return typeof img === 'string' && img.length > 0 && img.length <= 32 * 1024
} Prevention
- Send a short stable image reference (URL/hash) under 32 KiB, not the full base64.
- Pass position = null to clear the focal point instead of an object with empty image.
- Refresh the image key when the cover changes so stale large payloads are not replayed.
When it happens
Trigger: Frontend sends a non-null position with an empty Image string, or with an Image string longer than 32 KiB (a large base64-encoded cover). The 32 KiB cap exists because the image is stored as a position-cache key in av.CardCoverPositions, not as the actual asset.
Common situations: Plugin embeds the full image base64 instead of a short cache key; UI sends an empty Image because the cover URL was used instead; cover image changed and the stale payload was not refreshed, blowing past the limit.
Related errors
- invalid card cover source [%s]
- invalid card aspect ratio preset [%v]
- invalid card aspect ratio [%v]
- invalid card size preset [%v]
- invalid card width [%v]
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/c29a68e098f1eb32.
Report an issue: GitHub.