{"record":{"id":"ecfb846b48a2df59","repo":"xpzouying/xiaohongshu-mcp","slug":"w-ecfb84","errorCode":null,"errorMessage":"解析通知列表失败: %w","messagePattern":"解析通知列表失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"xiaohongshu/notification.go","lineNumber":303,"sourceCode":"// readTab 读取指定分区的原始数据，字段映射由结构体承担。\nfunc (n *NotificationAction) readTab(page *rod.Page, tab NotificationTab) (*notificationPayload, error) {\n\tres, err := page.Eval(`(tab) => {\n\t\tconst s = window.__INITIAL_STATE__;\n\t\tconst m = s && s.notification && s.notification.notificationMap;\n\t\treturn m && m[tab] ? JSON.stringify(m[tab]) : \"\";\n\t}`, string(tab))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"读取通知列表失败: %w\", err)\n\t}\n\n\traw := res.Value.String()\n\tif raw == \"\" {\n\t\treturn nil, fmt.Errorf(\"页面状态里没有分区 %s，可能未登录或页面结构已变化\", tab)\n\t}\n\n\tvar payload notificationPayload\n\tif err := json.Unmarshal([]byte(raw), &payload); err != nil {\n\t\treturn nil, fmt.Errorf(\"解析通知列表失败: %w\", err)\n\t}\n\treturn &payload, nil\n}\n\n// visible 判断一条通知的内容是否仍然正常可见。\nfunc (r rawNotification) visible() bool {\n\tif r.Comment.ID != \"\" && r.Comment.Illegal.Status != \"\" && r.Comment.Illegal.Status != statusNormal {\n\t\treturn false\n\t}\n\tif r.Item.ID != \"\" && r.Item.Illegal.Status != \"\" && r.Item.Illegal.Status != statusNormal {\n\t\treturn false\n\t}\n\treturn true\n}\n\n// convertNotifications 过滤掉不可见条目并转成对外结构，返回条目和被过滤的数量。\nfunc convertNotifications(raw []rawNotification, limit int) ([]NotificationItem, int) {\n\titems := make([]NotificationItem, 0, len(raw))","sourceCodeStart":285,"sourceCodeEnd":321,"githubUrl":"https://github.com/xpzouying/xiaohongshu-mcp/blob/332d196854a9eac0d2b8c2c0e3d0cc43139d724c/xiaohongshu/notification.go#L285-L321","documentation":"readTab 拿到分区 JSON 字符串后 json.Unmarshal 到 notificationPayload 失败：原始数据结构与结构体定义不符（前端改版）或 JSON 截断。","triggerScenarios":"readTab 反序列化 notificationMap[tab] 序列化结果失败：字段类型变化（如数字变字符串）、结构从对象变数组、负载中包含无法解析的数据形态。","commonSituations":"小红书前端升级后通知条目 JSON 字段改名/换类型；历史缓存的旧结构数据；JSON 中混入了非常规嵌套结构。","solutions":["打印 raw 内容对比 notificationPayload 结构体定义，修正 JSON tag","检查小红书前端是否改版，更新结构体字段映射","给结构体字段加上兼容类型（如 json.Number 或自定义 UnmarshalJSON）"],"exampleFix":"// before\nlikes  int    `json:\"likes\"`\n// after\nlikes  json.Number `json:\"likes\"`\nfunc (r *rawNotification) UnmarshalJSON(b []byte) error { /* 兼容新旧字段 */ }","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"items, err := n.List(ctx)\nif err != nil && strings.Contains(err.Error(), \"解析通知列表失败\") {\n    // 记录原始返回，升级库或上报结构变更\n    log.Printf(\"payload schema changed: %v\", err)\n    return fallbackLegacyPath()\n}","preventionTips":["结构体解析使用容错类型（json.Number、指针字段）","升级库版本时关注 payload 结构变更说明","对未知字段保留 json.RawMessage 以便排查","生产环境记录原始 JSON 样本便于诊断"],"tags":["go","json","unmarshal","schema-change"],"backgroundTag":"schema-validation-failed","analyzedSha":"332d196854a9eac0d2b8c2c0e3d0cc43139d724c","analyzedAt":"2026-09-05T22:22:55.988Z","contentChangedAt":"2026-09-05T22:22:55.988Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}