{"record":{"id":"5c9d8614d1fa01be","repo":"siyuan-note/siyuan","slug":"configuration-is-not-initialized","errorCode":null,"errorMessage":"configuration is not initialized","messagePattern":"configuration is not initialized","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/mcp/client/oauth_store.go","lineNumber":107,"sourceCode":"\t\tlogging.LogWarnf(\"mcp oauth: parse credentials failed: %s\", err)\n\t\treturn\n\t}\n\toauthCredentialStore.credentials = data.Credentials\n}\n\nfunc decryptOAuthCredentials(ciphertext string) (decrypted []byte) {\n\tdefer func() {\n\t\tif recovered := recover(); recovered != nil {\n\t\t\tlogging.LogWarnf(\"mcp oauth: decrypt credentials failed: %v\", recovered)\n\t\t\tdecrypted = nil\n\t\t}\n\t}()\n\treturn util.AESDecrypt(ciphertext)\n}\n\nfunc persistOAuthCredentialsLocked() error {\n\tif model.Conf == nil {\n\t\treturn fmt.Errorf(\"configuration is not initialized\")\n\t}\n\tdata, err := json.Marshal(&oauthCredentialData{Credentials: oauthCredentialStore.credentials})\n\tif err != nil {\n\t\treturn err\n\t}\n\tmodel.Conf.SetMCPOAuth(util.AESEncrypt(string(data)))\n\treturn nil\n}\n\nfunc getOAuthCredential(serverID, endpoint string) (oauthCredential, bool) {\n\toauthCredentialStore.Lock()\n\tdefer oauthCredentialStore.Unlock()\n\tloadOAuthCredentialsLocked()\n\tfor i := len(oauthCredentialStore.credentials) - 1; i >= 0; i-- {\n\t\tcredential := oauthCredentialStore.credentials[i]\n\t\tcredentialEndpoint := credential.Endpoint\n\t\tif credentialEndpoint == \"\" {\n\t\t\tcredentialEndpoint = credential.Resource","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/mcp/client/oauth_store.go#L89-L125","documentation":"persistOAuthCredentialsLocked serializes the in-memory MCP OAuth credential store and writes it into the kernel configuration via model.Conf.SetMCPOAuth. If model.Conf is nil the global configuration has not been bootstrapped, so persistence cannot proceed and the caller's put/remove/mark-rejected operation fails.","triggerScenarios":"Calling putOAuthCredential, removeOAuthCredential, or markOAuthCredentialRejected before model.Conf is loaded (e.g. very early in boot, in tests that never initialize the config, or before util.Boot/LoadConf ran).","commonSituations":"Unit tests that exercise the credential store without initializing the global conf; kernel code paths invoked before configuration load completes.","solutions":["Ensure the kernel configuration is loaded (model.Conf initialized) before performing MCP OAuth credential operations","In tests, initialize model.Conf (e.g. conf.NewAppConf or the test bootstrap helper) before calling the credential functions","Call the credential operations only from contexts that run after boot completes"],"exampleFix":"// before (test)\nputOAuthCredential(ctx, cred) // panics/errors: Conf nil\n// after\nmodel.Conf = conf.NewAppConf()\nputOAuthCredential(ctx, cred)","handlingStrategy":"type-guard","validationCode":"if model.Conf == nil { return errors.New(\"configuration not loaded yet\") }","typeGuard":"func confReady() bool { return model.Conf != nil }","tryCatchPattern":"if err := persistOAuthCredentialsLocked(); err != nil {\n    if strings.Contains(err.Error(), \"configuration is not initialized\") { /* defer or bootstrap conf */ }\n}","preventionTips":["Initialize the global conf in test setup before exercising credential store code","Only invoke OAuth credential operations after kernel boot completes","Add a startup assertion that model.Conf is non-nil before registering MCP services"],"tags":["configuration","oauth","initialization"],"backgroundTag":"missing-configuration","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"}