iawia002/lux · error

unable to get video ID

Error message

unable to get video ID

What it means

douyin.Extract resolves v.douyin.com share redirects manually, then requires /video/(\d+) in the resulting URL. This error means the resolved URL has no video path: the link points at something other than a standard video page. The subsequent ErrURLParseFailed check in the same block is effectively dead code — only this earlier branch fires.

Source

Thrown at extractors/douyin/douyin.go:59

		if err != nil {
			return nil, errors.WithStack(err)
		}
		c := http.Client{
			CheckRedirect: func(req *http.Request, via []*http.Request) error {
				return http.ErrUseLastResponse
			},
		}
		resp, err := c.Do(req)
		if err != nil {
			return nil, errors.WithStack(err)
		}
		defer resp.Body.Close() // nolint
		url = resp.Header.Get("location")
	}

	itemIds := utils.MatchOneOf(url, `/video/(\d+)`)
	if len(itemIds) == 0 {
		return nil, errors.New("unable to get video ID")
	}
	if itemIds == nil || len(itemIds) < 2 {
		return nil, errors.WithStack(extractors.ErrURLParseFailed)
	}
	itemId := itemIds[len(itemIds)-1]

	// dynamic generate cookie
	cookie, err := createCookie()
	if err != nil {
		return nil, errors.WithStack(err)
	}

	api := "https://www.douyin.com/aweme/v1/web/aweme/detail/?aweme_id=" + itemId
	// parse api query params string
	query, err := netURL.Parse(api)
	if err != nil {
		return nil, errors.WithStack(extractors.ErrURLQueryParamsParseFailed)
	}

View on GitHub (pinned to dd00f6d258)

Solutions

  1. Open the share link in a browser and pass the final www.douyin.com/video/<digits> URL instead.
  2. For image/note posts this extractor does not apply — use a tool that supports douyin images.
  3. Log the resolved URL after the redirect loop; if it is still v.douyin.com, the manual redirect following needs another hop.
  4. If douyin introduced new path shapes, extend the /video/(\d+) pattern.

Example fix

// before
itemIds := utils.MatchOneOf(url, `/video/(\d+)`)
// after — surface what the redirect produced before failing
fmt.Fprintln(os.Stderr, "douyin: resolved to", url)
itemIds := utils.MatchOneOf(url, `/(video|note)/(\d+)`)
Defensive patterns

Strategy: validation

Validate before calling

u := strings.TrimSpace(rawURL)
if strings.Contains(u, "v.douyin.com") {
	u = resolveShareLink(u) // follow the redirect yourself first
}
if utils.MatchOneOf(u, `/video/(\d+)`) == nil {
	return fmt.Errorf("not a douyin video link (resolved to %s)", u)
}

Type guard

func isDouyinVideoURL(u string) bool {
	return utils.MatchOneOf(u, `/video/(\d+)`) != nil
}

Try / catch

If caught, log the resolved URL alongside the error — it shows which non-video page (note/profile/live) the share link actually pointed to, which is the actionable datum.

Prevention

When it happens

Trigger: Share links that resolve to /note/ (image slideshows), user profiles or live pages; redirect chains where the location header was empty so the URL never gained the /video/ segment; douyin changing path formats.

Common situations: Copying app share text for photo posts; proxies altering or stripping redirects; douyin URL-scheme evolution.

Related errors


AI-assisted analysis of iawia002/lux@dd00f6d258 (2026-08-15). Data as JSON: /api/errors/cb7808f3114821fa. Report an issue: GitHub.