siyuan-note/siyuan · error

rollupFilters requires a configured rollup field

Error message

rollupFilters requires a configured rollup field

What it means

validateAttributeViewKeyFilters resolves which relation the filters apply to. For 'rollupFilters', the target field must be a rollup field that already has a configured Rollup object (set via the 'rollup' setting), because the rollup's RelationKeyID is needed to locate the underlying relation. A non-rollup field or a rollup with no configuration yet triggers this error.

Solutions

  1. Call UpdateAttributeViewKeyConfig with the 'rollup' setting first to configure the rollup, then set rollupFilters.
  2. Verify the field is a rollup field and has Rollup.RelationKeyID set before sending rollupFilters.
  3. If filters on the relation itself were intended, use 'relationFilters' on the relation field instead.

Example fix

// before
UpdateAttributeViewKeyConfig(avID, rollupKeyID, {"rollupFilters": [filter]})
// after
UpdateAttributeViewKeyConfig(avID, rollupKeyID, {"rollup": {"relationKeyID": relKeyID, "calc": ...}})
UpdateAttributeViewKeyConfig(avID, rollupKeyID, {"rollupFilters": [filter]})
Defensive patterns

Strategy: validation

Validate before calling

// JS: rollup must be configured before rollupFilters
if (key.type !== "rollup" || !key.rollup || !key.rollup.relationKeyID) throw new Error("rollupFilters requires a configured rollup field");

Type guard

function isConfiguredRollup(key) { return !!key && key.type === "rollup" && !!key.rollup && !!key.rollup.relationKeyID; }

Try / catch

try { await updateKeyConfig(avID, keyID, { rollupFilters: filters }); } catch (e) { if (String(e).includes("configured rollup field")) { await updateKeyConfig(avID, keyID, { rollup: rollupCfg }); await updateKeyConfig(avID, keyID, { rollupFilters: filters }); } else { throw e; } }

Prevention

When it happens

Trigger: Calling UpdateAttributeViewKeyConfig with {"rollupFilters": [...]} where key.Type != KeyTypeRollup, or the rollup field exists but 'rollup' was never configured (key.Rollup == nil).

Common situations: A script sets rollupFilters before configuring the rollup itself (wrong order of calls); a field of another type is mistaken for a rollup; a rollup's configuration was cleared earlier.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/b7a2fba6734fe47b. Report an issue: GitHub.

Appendix: source

Thrown at kernel/model/attribute_view_key_config.go:135

			if !ok {
				return errors.New("filters must be an array")
			}
			if err = validateAttributeViewKeyFilters(attrView, key, setting, filters); nil != err {
				return err
			}
			return setAttrViewColFilters(avID, "", keyID, filters, "relationFilters" == setting)
		default:
			return fmt.Errorf("unknown field setting: %s", setting)
		}
	}
	return
}

func validateAttributeViewKeyFilters(attrView *av.AttributeView, key *av.Key, setting string, value []any) error {
	relationKey := key
	if "rollupFilters" == setting {
		if av.KeyTypeRollup != key.Type || nil == key.Rollup {
			return errors.New("rollupFilters requires a configured rollup field")
		}
		var err error
		relationKey, err = attrView.GetKey(key.Rollup.RelationKeyID)
		if nil != err {
			return err
		}
	}
	if av.KeyTypeRelation != relationKey.Type || nil == relationKey.Relation {
		return errors.New("filters require a configured relation field")
	}
	dest, err := av.ParseAttributeView(relationKey.Relation.AvID)
	if nil != err {
		return err
	}
	var filters []*av.ViewFilter
	if err = decodeAttributeViewKeyConfig(value, &filters); nil != err {
		return err
	}

View on GitHub (pinned to 9f775e8a12)