{"record":{"id":"006e40bf4b80e828","repo":"siyuan-note/siyuan","slug":"conf-language-114","errorCode":null,"errorMessage":"Conf.Language(114)","messagePattern":"Conf\\.Language\\(114\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/tag.go","lineNumber":136,"sourceCode":"\n\tupdateAttributeViewBlockText(updateNodes)\n\n\tsql.FlushQueue()\n\tutil.PushClearProgress()\n\treturn\n}\n\nfunc RenameTag(oldLabel, newLabel string) (err error) {\n\tif invalidChar := treenode.ContainsMarker(newLabel); \"\" != invalidChar {\n\t\treturn fmt.Errorf(Conf.Language(112), invalidChar)\n\t}\n\n\tnewLabel = strings.TrimPrefix(newLabel, \"/\")\n\tnewLabel = strings.TrimSuffix(newLabel, \"/\")\n\tnewLabel = strings.TrimSpace(newLabel)\n\n\tif \"\" == newLabel {\n\t\treturn errors.New(Conf.Language(114))\n\t}\n\n\tif oldLabel == newLabel {\n\t\treturn\n\t}\n\n\tutil.PushEndlessProgress(Conf.Language(110))\n\tutil.RandomSleep(500, 1000)\n\n\ttags := sql.QueryTagSpansByLabel(oldLabel)\n\ttreeBlocks := map[string][]string{}\n\tfor _, tag := range tags {\n\t\tif blocks, ok := treeBlocks[tag.RootID]; !ok {\n\t\t\ttreeBlocks[tag.RootID] = []string{tag.BlockID}\n\t\t} else {\n\t\t\ttreeBlocks[tag.RootID] = append(blocks, tag.BlockID)\n\t\t}\n\t}","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/tag.go#L118-L154","documentation":"After ContainsMarker passes, RenameTag trims leading/trailing '/' and whitespace; if the result is empty it returns Conf.Language(114) = 'Tag cannot be empty'. This catches labels that are only markers, slashes, or spaces (e.g. '#', '/', '   ', '/#') which survived the marker check but hold no real content.","triggerScenarios":"POST /api/tag/renameTag with newLabel that is empty, all whitespace, only '/' separators, or after marker stripping becomes empty. Typing only spaces or slashes in the rename field.","commonSituations":"User clears the rename field and submits. Label is just '/'. Label after removing a leading '#' leaves nothing. Programmatic rename with an uninitialized string.","solutions":["Provide a non-empty label containing at least one non-marker, non-slash character.","Frontend: disable Rename when the trimmed field is empty.","If renaming to remove a tag, use the delete-tag flow instead of renaming to empty."],"exampleFix":"// before: newLabel=\"/\" -> error 114\n// after: newLabel=\"work\"","handlingStrategy":"validation","validationCode":"// Go caller\nlabel := strings.TrimSpace(strings.TrimSuffix(strings.TrimPrefix(newLabel, \"/\"), \"/\"))\nif label == \"\" {\n    return errors.New(\"tag label cannot be empty\")\n}","typeGuard":"// Go\nfunc nonEmptyTagLabel(label string) bool {\n    t := strings.TrimSpace(strings.TrimSuffix(strings.TrimPrefix(label, \"/\"), \"/\"))\n    return t != \"\"\n}","tryCatchPattern":null,"preventionTips":["Disable the Rename submit button when the field is blank.","Run the same trim-then-empty check on the client.","Distinguish 'rename to empty' from 'delete tag' in the UI."],"tags":["tag","validation","i18n","kernel"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}