{"record":{"id":"4e4bc3212b783906","repo":"iawia002/lux","slug":"data-message","errorCode":null,"errorMessage":"data.Message","messagePattern":"data\\.Message","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"extractors/yinyuetai/yinyuetai.go","lineNumber":61,"sourceCode":"\tif vid == nil || len(vid) < 2 {\n\t\treturn nil, errors.New(\"invalid url for yinyuetai\")\n\t}\n\tparams := fmt.Sprintf(\"videoId=%s\", vid[1])\n\t// generate api url\n\tapiURL := genAPI(actionGetMvInfo, params)\n\tvar err error\n\thtml, err := request.Get(apiURL, url, nil)\n\tif err != nil {\n\t\treturn nil, errors.WithStack(err)\n\t}\n\t// parse yinyuetai data\n\tdata := yinyuetaiMvData{}\n\tif err = json.Unmarshal([]byte(html), &data); err != nil {\n\t\treturn nil, errors.WithStack(extractors.ErrURLParseFailed)\n\t}\n\t// handle api error\n\tif data.Error {\n\t\treturn nil, errors.New(data.Message)\n\t}\n\tif data.VideoInfo.CoreVideoInfo.Error {\n\t\treturn nil, errors.New(data.VideoInfo.CoreVideoInfo.ErrorMsg)\n\t}\n\ttitle := data.VideoInfo.CoreVideoInfo.VideoName\n\tstreams := make(map[string]*extractors.Stream, len(data.VideoInfo.CoreVideoInfo.VideoURLModels))\n\t// set streams\n\tfor _, model := range data.VideoInfo.CoreVideoInfo.VideoURLModels {\n\t\turlData := &extractors.Part{\n\t\t\tURL:  model.VideoURL,\n\t\t\tSize: model.FileSize,\n\t\t\tExt:  \"mp4\",\n\t\t}\n\t\tstreams[model.QualityLevel] = &extractors.Stream{\n\t\t\tParts:   []*extractors.Part{urlData},\n\t\t\tSize:    model.FileSize,\n\t\t\tQuality: model.QualityLevelName,\n\t\t}","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/iawia002/lux/blob/dd00f6d258d80b6684a0b9402d7124e5c18ef42f/extractors/yinyuetai/yinyuetai.go#L43-L79","documentation":"After the YinYueTai getMvInfo API responds and the JSON is unmarshalled, a top-level Error flag of true means the API itself rejected the request; the API's own Message field becomes the error text. This is an application-level error from YinYueTai, not a transport or parse failure.","triggerScenarios":"The videoId extracted from the URL is invalid or deleted, the MV is geo-restricted, or YinYueTai's API error envelope changed so Error is set on otherwise-fine responses.","commonSituations":"Dead MV links in old playlists; API behavior drift after site updates; ids that only resolve for logged-in or mainland users.","solutions":["Open the video page in a browser and confirm the MV still exists and plays from your region","Try the alternate URL form (video/h5/<id> or m2 video.html?id=) which resolves to the same id — if the id is valid the API call should succeed","Print data.Msg from the API response to see YinYueTai's own reason and act on it","Skip the URL in batch runs when the API consistently reports errors for it"],"exampleFix":"// before\n_, err := yinyuetai.Extract(url, opts)\nif err != nil { return err }\n\n// after\n_, err := yinyuetai.Extract(url, opts)\nif err != nil {\n    log.Printf(\"yinyuetai API rejected %s: %v\", url, err)\n    if strings.Contains(err.Error(), \"不存在\") || strings.Contains(err.Error(), \"not exist\") {\n        continue // dead MV, skip\n    }\n    return err\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"_, err := yinyuetai.Extract(url, opts)\nif err != nil {\n    // err.Error() is the API's own Message; treat non-empty Message as terminal\n    if strings.Contains(err.Error(), \"invalid url\") {\n        // URL shape problem: fix input\n    } else {\n        // API refusal (dead/geo MV): skip\n    }\n    return err\n}","preventionTips":["Distinguish URL-shape errors ('invalid url for yinyuetai') from API refusals by message","Cache API refusal verdicts per video id so batch runs do not re-query dead MVs","Verify MVs exist in a browser before queuing them"],"tags":["yinyuetai","api-error","geo-restriction"],"backgroundTag":null,"analyzedSha":"dd00f6d258d80b6684a0b9402d7124e5c18ef42f","analyzedAt":"2026-08-15T16:57:31.080Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}