{"record":{"id":"530f5dff252d4cdc","repo":"siyuan-note/siyuan","slug":"encrypted-notebook-cannot-be-saved-as-a-normal-not","errorCode":null,"errorMessage":"encrypted notebook cannot be saved as a normal notebook","messagePattern":"encrypted notebook cannot be saved as a normal notebook","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/box_conf_crypto.go","lineNumber":99,"sourceCode":"\tif err := decryptBoxMetadata(boxID, boxConf, dek); err != nil {\n\t\tsetEncryptedBoxState(boxID, EncryptedBoxStateError)\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc prepareBoxConfForSave(boxID string, boxConf *conf.BoxConf) (*conf.BoxConf, error) {\n\tif boxConf == nil {\n\t\treturn nil, errors.New(\"notebook configuration is missing\")\n\t}\n\tpersisted := *boxConf\n\tpersisted.BoxCrypt = DeepCopyBoxEncryption(boxConf.BoxCrypt)\n\tif persisted.Encrypted {\n\t\tforgetRuntimeNormalBox(boxID)\n\t}\n\tif !persisted.Encrypted {\n\t\tif IsEncryptedBox(boxID) {\n\t\t\treturn nil, errors.New(\"encrypted notebook cannot be saved as a normal notebook\")\n\t\t}\n\t\treturn &persisted, nil\n\t}\n\tif persisted.BoxCrypt == nil {\n\t\tclearBoxMetadata(&persisted)\n\t\treturn &persisted, nil\n\t}\n\tif GetEncryptedBoxState(boxID) == EncryptedBoxStateError {\n\t\treturn nil, errors.New(\"encrypted notebook is in an error state\")\n\t}\n\n\tif dek, ok := cachedDEKCopy(boxID); ok {\n\t\tdefer zeroAndClear(dek)\n\t\tif err := reuseBoxMetadataIfUnchanged(boxID, &persisted, dek); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t} else if len(persisted.BoxCrypt.Metadata) == 0 {\n\t\texisting, err := readRawBoxConf(boxID)","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/box_conf_crypto.go#L81-L117","documentation":"prepareBoxConfForSave downgrade guard: the incoming conf marks the notebook as not encrypted, but the notebook is currently registered as encrypted on disk. Saving would silently drop the encryption envelope, so the save is refused — the notebook must be properly decrypted/unlocked through the encrypted-notebook flow first.","triggerScenarios":"Thrown at kernel/model/box_conf_crypto.go:99 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Use the proper decrypt/remove-protection flow to convert the notebook to normal","Do not hand-edit conf.json of an encrypted notebook","If the state is stale, verify with GetEncryptedBoxState before retrying"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}