siyuan-note/siyuan · warning

attribute view [%s] changed while loading search info

Error message

attribute view [%s] changed while loading search info

What it means

Logged and returned by loadAttributeViewSearchInfoInBox when cache.SetAVSearchDataInBox returns false after successfully parsing the AV data — meaning the on-disk data version no longer matches the version captured at read time. The AV was concurrently modified/saved (bumping its version) between the read and the cache-write, so the parsed search info was discarded as stale. This is a warn-level race signal, not data corruption.

Source

Thrown at kernel/av/av.go:671

			if avBoxID != "" {
				if data, err = decryptAVDataLocked(avBoxID, avID, data); err != nil {
					logging.LogErrorf("decrypt attribute view [%s] failed: %s", avJSONPath, err)
					return
				}
			} else if util.IsCiphertext(data) {
				return nil, nil
			}
		}

		if ret, err = parseAttributeViewSearchInfo(data); err != nil {
			logging.LogErrorf("unmarshal attribute view search info [%s] failed: %s", avID, err)
			return nil, err
		}
		if cache.SetAVSearchDataInBox(avID, avBoxID, dataVersion, ret) {
			return ret, nil
		}
	}
	err = fmt.Errorf("attribute view [%s] changed while loading search info", avID)
	logging.LogWarnf("%s", err)
	return nil, err
}

func GetAttributeViewContent(avID string) (content string) {
	if "" == avID {
		return
	}

	attrView, err := ParseAttributeView(avID)
	if err != nil {
		logging.LogErrorf("parse attribute view [%s] failed: %s", avID, err)
		return
	}
	if nil == attrView {
		return
	}
	return getAttributeViewContent0(attrView)

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Retry the search-info read; the next attempt will pick up the new version and cache it.
  2. Reduce concurrent writers on the same AV (serialize saves) if the warning is frequent.
  3. Treat as benign in logs unless it persists for the same avID indefinitely, which would indicate a stuck version bump.

Example fix

// before
info, err := av.GetAttributeViewSearchInfoInBox(avID, boxID)

// after: retry once on the stale-version race
info, err := av.GetAttributeViewSearchInfoInBox(avID, boxID)
if err != nil && strings.Contains(err.Error(), "changed while loading") {
    info, err = av.GetAttributeViewSearchInfoInBox(avID, boxID)
}
Defensive patterns

Strategy: retry

Try / catch

info, err := av.GetAttributeViewSearchInfoInBox(avID, boxID)
if err != nil && strings.Contains(err.Error(), "changed while loading") {
    // AV was saved concurrently; one retry picks up the new version
    info, err = av.GetAttributeViewSearchInfoInBox(avID, boxID)
}

Prevention

When it happens

Trigger: Concurrent API calls: one thread loads search info (reads AV JSON at version N) while another thread saves the same AV (bumping version to N+1). When the loader tries to cache, the version check fails. Happens under rapid edits, sync, or background re-indexing touching the same AV.

Common situations: Two browser tabs editing the same database; a sync pull landing while the user is filtering; batch operations iterating AVs while one is being saved; full-text re-index racing an interactive edit.

Related errors


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