iawia002/lux · error
Could not read page data
Error message
Could not read page data
What it means
Thrown by the Odysee extractor when the fetched claim page's bytes do not contain a <script type="application/ld+json">...</script> block matching the regex. The LD-JSON payload is how the extractor finds ContentURL, so without it nothing can be extracted. The page downloaded fine but its structure is not what the extractor expects.
Solutions
- Dump the response body (err is nil, so re-fetch the URL manually with the same headers) and inspect what page Odysee actually served
- Confirm the claim URL opens in a browser and shows a video with an ld+json block in view-source
- If the markup changed, update regScript in extractors/odysee/odysee.go to match the current script tag layout
- If a challenge page is served, retry from a residential IP or with browser-like headers
Example fix
// before
matchPayload := regScript.FindSubmatch(b)
if len(matchPayload) < 2 {
return nil, errors.New("Could not read page data")
}
// after (diagnose what was actually served before failing)
matchPayload := regScript.FindSubmatch(b)
if len(matchPayload) < 2 {
return nil, fmt.Errorf("could not read page data: no ld+json block in %d bytes (served title: %q)",
len(b), utils.MatchOneOf(string(b), `<title>(.*?)</title>`))
} Defensive patterns
Strategy: try-catch
Try / catch
_, err := odysee.Extract(url, opts)
if err != nil {
if strings.Contains(err.Error(), "Could not read page data") {
// page served without ld+json: markup change or bot wall; log and skip
}
return err
} Prevention
- Monitor Odysee markup changes; this error is the first symptom of a regex drift
- Fetch with browser-like headers from non-datacenter IPs to avoid challenge pages
- Wrap batch runs so one changed page does not abort everything
When it happens
Trigger: Calling Extract on an Odysee claim URL where the server returns an error page, an anti-bot/consent interstitial, or a redesigned page whose ld+json script tag no longer matches `(?im)<script type="application\/ld+json">([\s\S]*)[\n?]</script>`. Also triggered by a mistyped claim name that yields a non-content page.
Common situations: Odysee front-end markup changed after the regex was written, datacenter IP blocked and served a challenge page, or the URL points at a channel/livestream rather than a claim with a playable content URL.
Related errors
- can't match gif content downloadable url
- can't match mp4 content downloadable url
- empty list
- ErrURLParseFailed
- zhihu video id extract failed
AI-assisted analysis of iawia002/lux@dd00f6d258 (2026-08-15).
Data as JSON: /api/errors/663af2f15f5af621.
Report an issue: GitHub.
Appendix: source
Thrown at extractors/odysee/odysee.go:61
switch res.Header.Get("Content-Encoding") {
case "gzip":
reader, _ = gzip.NewReader(res.Body)
case "deflate":
reader = flate.NewReader(res.Body)
default:
reader = res.Body
}
defer reader.Close() // nolint
b, err := io.ReadAll(reader)
if err != nil {
return nil, errors.WithStack(err)
}
regScript := regexp.MustCompile(`(?im)\<script type="application\/ld\+json"\>([\s\S]*)[\n?]<\/script>`)
matchPayload := regScript.FindSubmatch(b)
if len(matchPayload) < 2 {
return nil, errors.New("Could not read page data")
}
var resData odyseePayload
if err := json.Unmarshal(matchPayload[1], &resData); err != nil {
return nil, errors.WithStack(err)
}
streams := make(map[string]*extractors.Stream, 1)
size, err := request.Size(resData.ContentURL, u)
if err != nil {
return nil, errors.WithStack(err)
}
streams["Default"] = &extractors.Stream{
Parts: []*extractors.Part{
{
URL: resData.ContentURL,
Size: size,View on GitHub (pinned to dd00f6d258)