{"record":{"id":"420820890e40a728","repo":"iawia002/lux","slug":"string-playauth-error","errorCode":null,"errorMessage":"string(playAuth.Error)","messagePattern":"string\\(playAuth\\.Error\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"extractors/geekbang/geekbang.go","lineNumber":130,"sourceCode":"\tif data.Data.VideoID == \"\" && !data.Data.ColumnHadSub {\n\t\treturn nil, errors.New(\"请先购买课程，或使用Cookie登录。\")\n\t}\n\n\t// Get video license token information\n\tparams = strings.NewReader(\"{\\\"source_type\\\":1,\\\"aid\\\":\" + matches[2] + \",\\\"video_id\\\":\\\"\" + data.Data.VideoID + \"\\\"}\")\n\tres, err = request.Request(http.MethodPost, \"https://time.geekbang.org/serv/v3/source_auth/video_play_auth\", params, heanders)\n\tif err != nil {\n\t\treturn nil, errors.WithStack(err)\n\t}\n\tdefer res.Body.Close() // nolint\n\n\tvar playAuth videoPlayAuth\n\tif err = json.NewDecoder(res.Body).Decode(&playAuth); err != nil {\n\t\treturn nil, errors.WithStack(err)\n\t}\n\n\tif playAuth.Code < 0 {\n\t\treturn nil, errors.New(string(playAuth.Error))\n\t}\n\n\t// Get video playback information\n\theanders = map[string]string{\"Accept-Encoding\": \"\"}\n\tres, err = request.Request(http.MethodGet, \"http://ali.mantv.top/play/info?playAuth=\"+playAuth.Data.PlayAuth, nil, heanders)\n\tif err != nil {\n\t\treturn nil, errors.WithStack(err)\n\t}\n\tdefer res.Body.Close() // nolint\n\n\tvar playInfo playInfo\n\tif err = json.NewDecoder(res.Body).Decode(&playInfo); err != nil {\n\t\treturn nil, errors.WithStack(err)\n\t}\n\n\ttitle := data.Data.Title\n\n\tstreams := make(map[string]*extractors.Stream, len(playInfo.PlayInfoList.PlayInfo))","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/iawia002/lux/blob/dd00f6d258d80b6684a0b9402d7124e5c18ef42f/extractors/geekbang/geekbang.go#L112-L148","documentation":"The second geekbang call, serv/v3/source_auth/video_play_auth, returned code < 0 and its raw error JSON (a json.RawMessage) is surfaced verbatim. The article lookup succeeded but the play-license step was rejected — expired auth, video_id mismatch, or server-side throttling.","triggerScenarios":"A cookie valid for article info but rejected for play auth; batch runs where the license request goes stale; a changed v3 API contract; rate limiting after many sequential downloads.","commonSituations":"Long queues of geekbang URLs; old exported cookies; API behavior changes after maintenance windows.","solutions":["Retry the single failing URL — play-auth rejections are often transient.","Re-export a fresh cookie and retry the batch.","Log the raw playAuth JSON body to see the server's exact reason."],"exampleFix":"// before\nif playAuth.Code < 0 {\n\treturn nil, errors.New(string(playAuth.Error))\n}\n// after — include the server code and raw reason\nif playAuth.Code < 0 {\n\treturn nil, fmt.Errorf(\"video_play_auth failed (code %d): %s\", playAuth.Code, string(playAuth.Error))\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"Retry the failing URL once after a short delay and, if it persists, with a freshly exported cookie; the play-auth step is stateful and often transiently rejected. Surface the raw playAuth.Error JSON when giving up.","preventionTips":["Keep geekbang batches short so licenses and cookies do not go stale mid-run","Re-export cookies between long sessions","Log the playAuth response body on failure — the server states its reason there"],"tags":["geekbang","auth","api","transient"],"backgroundTag":null,"analyzedSha":"dd00f6d258d80b6684a0b9402d7124e5c18ef42f","analyzedAt":"2026-08-15T16:57:31.080Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}