{"record":{"id":"20b95e6159167ae1","repo":"siyuan-note/siyuan","slug":"notebook-configuration-is-missing","errorCode":null,"errorMessage":"notebook configuration is missing","messagePattern":"notebook configuration is missing","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/box_conf_crypto.go","lineNumber":90,"sourceCode":"}\n\nfunc revealBoxMetadataIfUnlocked(boxID string, boxConf *conf.BoxConf) error {\n\tclearBoxMetadata(boxConf)\n\tdek, ok := cachedDEKCopy(boxID)\n\tif !ok {\n\t\treturn nil\n\t}\n\tdefer zeroAndClear(dek)\n\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\")","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/box_conf_crypto.go#L72-L108","documentation":"This sentinel validation error fires in prepareBoxConfForSave when the box configuration pointer passed in is nil. SaveConf calls it while persisting a notebook's settings, so a nil conf means the caller attempted to save a notebook without a configuration object — a programming/initialization defect rather than bad user input, since a loaded notebook always has a BoxConf. The save is aborted so an empty or partially initialized struct is never written to disk, which would wipe fields such as BoxCrypt. Callers handle it via try-catch/propagation: the returned error surfaces through the SaveConf API call.","triggerScenarios":"Thrown at kernel/model/box_conf_crypto.go:90 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Check the caller that resolves the BoxConf for the notebook ID","Ensure the notebook exists before attempting to save its configuration"],"exampleFix":null,"handlingStrategy":"type-guard","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-14T00:17:10.932Z"}