{"record":{"id":"22aca9bd1cfec7c7","repo":"lyswhut/lx-music-desktop","slug":"error-22aca9","errorCode":null,"errorMessage":"获取歌曲详情失败","messagePattern":"获取歌曲详情失败","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/renderer/utils/musicSdk/wy/musicDetail.js","lineNumber":108,"sourceCode":"    // console.log(list)\n    return list\n  },\n  async getList(ids = [], retryNum = 0) {\n    if (retryNum > 2) return Promise.reject(new Error('try max num'))\n\n    const requestObj = httpFetch('https://music.163.com/weapi/v3/song/detail', {\n      method: 'post',\n      headers: {\n        'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36',\n        origin: 'https://music.163.com',\n      },\n      form: weapi({\n        c: '[' + ids.map(id => ('{\"id\":' + id + '}')).join(',') + ']',\n        ids: '[' + ids.join(',') + ']',\n      }),\n    })\n    const { body, statusCode } = await requestObj.promise\n    if (statusCode != 200 || body.code !== 200) throw new Error('获取歌曲详情失败')\n    // console.log(body)\n    return { source: 'wy', list: this.filterList(body) }\n  },\n}\n","sourceCodeStart":90,"sourceCodeEnd":113,"githubUrl":"https://github.com/lyswhut/lx-music-desktop/blob/9c364b482e5621a1d38b50e8610d2fb974457e6e/src/renderer/utils/musicSdk/wy/musicDetail.js#L90-L113","documentation":"Thrown by Netease's musicDetail.getList when the song detail endpoint at https://music.163.com/weapi/v3/song/detail returns non-200 or body.code !== 200. Uses weapi encryption with a batch of song IDs (c and ids arrays). Has a retry guard (retryNum > 2) that fires first. Takes an array of ids and constructs the weapi form by JSON-stringifying them. Reads the entire body via filterList(body).","triggerScenarios":"The weapi encryption is broken. One or more IDs in the batch are invalid or removed (Netease may return non-200 for partially-invalid batches). Empty ids array produces malformed weapi form. Rate-limiting or IP-banning. Netease changes the v3/song/detail endpoint contract.","commonSituations":"Passing an empty ids array (default is []) produces a request with empty c/ids arrays, which Netease may reject. The weapi key rotation breaks all encrypted requests. Non-CN IP blocking. Mixing IDs from different providers in the same batch.","solutions":["Guard against an empty ids array before making the request.","Log body.code and statusCode to diagnose encryption vs. rate-limiting.","Verify all IDs are valid Netease song IDs (numeric strings).","Retry by calling getList(ids, retryNum + 1) since it supports bounded retries.","Use a CN proxy if running from outside China."],"exampleFix":"// before\nasync getList(ids = [], retryNum = 0) {\n  if (retryNum > 2) return Promise.reject(new Error('try max num'))\n  const requestObj = httpFetch('https://music.163.com/weapi/v3/song/detail', { ... })\n  const { body, statusCode } = await requestObj.promise\n  if (statusCode != 200 || body.code !== 200) throw new Error('获取歌曲详情失败')\n  return { source: 'wy', list: this.filterList(body) }\n}\n\n// after\nasync getList(ids = [], retryNum = 0) {\n  if (!ids.length) return { source: 'wy', list: [] }\n  if (retryNum > 2) return Promise.reject(new Error('try max num'))\n  const requestObj = httpFetch('https://music.163.com/weapi/v3/song/detail', { ... })\n  const { body, statusCode } = await requestObj.promise\n  if (statusCode != 200 || !body || body.code !== 200) {\n    console.warn('wy musicDetail failed', { statusCode, code: body?.code })\n    if (retryNum < 2) return this.getList(ids, retryNum + 1)\n    throw new Error('获取歌曲详情失败')\n  }\n  return { source: 'wy', list: this.filterList(body) }\n}","handlingStrategy":"validation","validationCode":"function isValidDetailRequest(ids) {\n  return Array.isArray(ids) && ids.length > 0 && ids.every(id => typeof id === 'string' && /^\\d+$/.test(id))\n}","typeGuard":"function isWyMusicDetailResponse(body) {\n  return body != null && typeof body === 'object' && body.code === 200 && body.songs != null\n}","tryCatchPattern":"try {\n  if (!ids.length) return { source: 'wy', list: [] }\n  const result = await wyMusicDetail.getList(ids)\n} catch (err) {\n  if (err.message === '获取歌曲详情失败') {\n    console.warn('Netease song detail failed for ids', ids, '(check weapi keys / IP blocking)')\n    return { source: 'wy', list: [] }\n  }\n  throw err\n}","preventionTips":["Guard against an empty ids array before calling getList.","Verify all IDs are valid numeric Netease song IDs.","Keep weapi encryption keys updated.","Call getList with a retryNum parameter to leverage built-in retries.","Use a CN proxy if running from outside China.","Log body.code and statusCode to diagnose encryption vs. rate-limiting."],"tags":["netease","song-detail","network","api-contract","weapi-encryption","https","rate-limiting"],"backgroundTag":null,"analyzedSha":"9c364b482e5621a1d38b50e8610d2fb974457e6e","analyzedAt":"2026-08-12T15:14:48.244Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}