{"record":{"id":"bb75140e127847ff","repo":"fish2018/pansou","slug":"w-bb7514","errorCode":null,"errorMessage":"迁移旧站点配置失败: %w","messagePattern":"迁移旧站点配置失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/gying/gying.go","lineNumber":701,"sourceCode":"\t\treturn err\n\t}\n\n\tvar config GyingConfig\n\tif err := json.Unmarshal(data, &config); err != nil {\n\t\treturn err\n\t}\n\tif config.BaseURL == \"\" {\n\t\treturn nil\n\t}\n\n\tbaseURL, err := normalizeBaseURL(config.BaseURL)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif isLegacyGyingBaseURL(baseURL) {\n\t\tbaseURL = DefaultGyingBaseURL\n\t\tif err := p.saveConfig(baseURL); err != nil {\n\t\t\treturn fmt.Errorf(\"迁移旧站点配置失败: %w\", err)\n\t\t}\n\t}\n\tp.setBaseURL(baseURL)\n\treturn nil\n}\n\nfunc (p *GyingPlugin) saveConfig(baseURL string) error {\n\tconfig := GyingConfig{\n\t\tBaseURL:   baseURL,\n\t\tUpdatedAt: time.Now(),\n\t}\n\n\tdata, err := json.MarshalIndent(config, \"\", \"  \")\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn ioutil.WriteFile(p.configPath(), data, 0644)\n}","sourceCodeStart":683,"sourceCodeEnd":719,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/gying/gying.go#L683-L719","documentation":"Thrown at plugin/gying.go:701 during config load/upgrade. When the stored baseURL matches a legacy URL form (isLegacyGyingBaseURL), the plugin rewrites it to DefaultGyingBaseURL and calls p.saveConfig; if persisting the migrated value fails, the write error is wrapped with this message.","triggerScenarios":"Plugin startup or config load where an old-format baseURL is detected AND saving the new default fails — typically because the config file is read-only, the directory is missing, or disk is full.","commonSituations":"Upgrading the plugin while running under a read-only filesystem or a user without write permission to the config/cache directory; config file corrupted or locked by another process.","solutions":["Inspect the wrapped %w cause to see the actual save failure (permission, path, disk).","Ensure the plugin's config/cache directory exists and is writable by the process user (chmod/chown as needed).","Manually update the stored baseURL to the current default so migration is skipped on next start.","Check for another process holding the config file and retry after freeing it."],"exampleFix":"// before (read-only dir)\nchmod 555 ./cache\n// after\nchmod 755 ./cache && chown $USER ./cache","handlingStrategy":"try-catch","validationCode":"// check config dir writability before load\ninfo, err := os.Stat(configDir)\nif err != nil || !info.IsDir() { return fmt.Errorf(\"config dir missing: %s\", configDir) }\nif err := os.WriteFile(filepath.Join(configDir, \".wtest\"), nil, 0644); err != nil { return fmt.Errorf(\"config dir not writable\") }\nos.Remove(filepath.Join(configDir, \".wtest\"))","typeGuard":null,"tryCatchPattern":"if err := p.loadConfig(); err != nil {\n\tif strings.Contains(err.Error(), \"迁移旧站点配置失败\") {\n\t\tlog.Printf(\"config migration failed, fix permissions on config dir: %v\", err)\n\t}\n\treturn err\n}","preventionTips":["Keep the plugin's config/cache directory writable by the service user after upgrades.","Pre-update stored baseURLs to the current default to avoid triggering migration.","Monitor disk space on the host running the plugin."],"tags":["config","migration","file-write"],"backgroundTag":"file-write-failed","analyzedSha":"beaa56133755a548ebc51b090b3816e2ae044aa6","analyzedAt":"2026-09-07T00:31:18.025Z","contentChangedAt":"2026-09-07T00:31:18.025Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}