siyuan-note/siyuan · warning

Conf.Language(114)

Error message

Conf.Language(114)

What it means

RenameTag refuses to rename a tag to an empty label. After stripping leading/trailing slashes and whitespace from newLabel, if nothing remains the kernel returns the localized message Conf.Language(114) = "Tag cannot be empty". Tags in SiYuan are hierarchical ("/parent/child/"), so the slash trimming is normal normalization; only a fully-empty result is rejected.

Solutions

  1. Pass a non-empty newLabel containing at least one non-slash, non-whitespace character
  2. Check the normalized label client-side (trim spaces and '/') before calling renameTag and show a validation message instead
  3. If migrating from an old tag value that was itself empty, remove the tag with RemoveTag instead of renaming it to ""

Example fix

// before
renameTag(oldLabel, "") // error: Tag cannot be empty
// after
const newLabel = input.trim()
if (newLabel) { await fetchPost("/api/tag/renameTag", {oldLabel, newLabel}) }
Defensive patterns

Strategy: validation

Validate before calling

const normalized = newLabel.replace(/^\/+|\/+$/g, "").trim();
if (!normalized) throw new Error("Tag cannot be empty");

Prevention

When it happens

Trigger: Calling /api/tag/renameTag (model.RenameTag) with newLabel that is empty, only whitespace, only slashes ("/", "///"), or a mix like " / " — all normalize to "".

Common situations: A plugin or UI script clears the rename input before submitting; batch rename scripts iterating a tag list where one entry is blank; trimming logic upstream already removed the text the user typed.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at kernel/model/tag.go:136

	updateAttributeViewBlockText(updateNodes)

	sql.FlushQueue()
	util.PushClearProgress()
	return
}

func RenameTag(oldLabel, newLabel string) (err error) {
	if invalidChar := treenode.ContainsMarker(newLabel); "" != invalidChar {
		return fmt.Errorf(Conf.Language(112), invalidChar)
	}

	newLabel = strings.TrimPrefix(newLabel, "/")
	newLabel = strings.TrimSuffix(newLabel, "/")
	newLabel = strings.TrimSpace(newLabel)

	if "" == newLabel {
		return errors.New(Conf.Language(114))
	}

	if oldLabel == newLabel {
		return
	}

	util.PushEndlessProgress(Conf.Language(110))
	util.RandomSleep(500, 1000)

	tags := sql.QueryTagSpansByLabel(oldLabel)
	treeBlocks := map[string][]string{}
	for _, tag := range tags {
		if blocks, ok := treeBlocks[tag.RootID]; !ok {
			treeBlocks[tag.RootID] = []string{tag.BlockID}
		} else {
			treeBlocks[tag.RootID] = append(blocks, tag.BlockID)
		}
	}

View on GitHub (pinned to 9f775e8a12)