fish2018/pansou · error

JWT Payload中没有链接

Error message

JWT Payload中没有链接

What it means

After successfully unmarshalling the JWT payload, decodeJWTURL checks that data.url is a non-empty string. This error is thrown when the JSON parsed fine but contains no usable link at data.url — the struct fields remain zero-valued. It is a domain validation that the decoded token actually carries a redirect target.

Solutions

  1. Dump the decoded payload JSON to confirm where the URL actually lives and update the struct path (data.url vs url vs target).
  2. Treat such tokens as invalid inputs and skip/refresh them from the source page instead of decoding.
  3. Add an upstream schema check: fetch a fresh token and verify it contains data.url before relying on cached behavior.
  4. If the URL legitimately may be empty, return the error to callers but make the message point at the missing field for faster diagnosis.

Example fix

// before
if strings.TrimSpace(payloadData.Data.URL) == "" {
    return "", fmt.Errorf("JWT Payload中没有链接")
}
// after: point at the actual payload for diagnosis
if strings.TrimSpace(payloadData.Data.URL) == "" {
    return "", fmt.Errorf("JWT Payload中没有链接 (payload=%s)", string(payload))
}
Defensive patterns

Strategy: validation

Validate before calling

var probe struct {
    Data struct {
        URL string `json:"url"`
    } `json:"data"`
}
if err := json.Unmarshal(payload, &probe); err != nil {
    return err
}
if strings.TrimSpace(probe.Data.URL) == "" {
    return errors.New("token payload carries no url — skip this item")
}

Type guard

func payloadHasURL(payload []byte) bool {
    var p struct {
        Data struct {
            URL string `json:"url"`
        } `json:"data"`
    }
    if json.Unmarshal(payload, &p) != nil {
        return false
    }
    return strings.TrimSpace(p.Data.URL) != ""
}

Try / catch

url, err := decodeJWTURL(jwtToken)
if errors.Is(err, errNoLinkInPayload) || strings.Contains(err.Error(), "没有链接") {
    log.Printf("token %s… has no embedded link, skipping item", jwtToken[:12])
    continue
}
if err != nil {
    return err
}

Prevention

When it happens

Trigger: getButtonDetail passes a JWT whose payload JSON parses but has an empty or missing data.url field, e.g. {"data":{"url":""}} or a payload with other claims only.

Common situations: Upstream site issues tokens without embedded links for certain buttons (login/dead buttons); the payload schema changed so the URL now sits at a different JSON path; whitespace-only url values (TrimSpace catches those too).

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07). Data as JSON: /api/errors/7aa84a81c730b50d. Report an issue: GitHub.

Appendix: source

Thrown at plugin/susu/susu.go:536

	}

	// 解码Payload
	payload, err := base64.RawURLEncoding.DecodeString(parts[1])
	if err != nil {
		return "", fmt.Errorf("解码Payload失败: %w", err)
	}

	// 解析JSON
	var payloadData struct {
		Data struct {
			URL string `json:"url"`
		} `json:"data"`
	}
	if err := json.Unmarshal(payload, &payloadData); err != nil {
		return "", fmt.Errorf("解析Payload JSON失败: %w", err)
	}
	if strings.TrimSpace(payloadData.Data.URL) == "" {
		return "", fmt.Errorf("JWT Payload中没有链接")
	}

	// 缓存结果
	jwtDecodeCache.Store(jwtToken, payloadData.Data.URL)

	return payloadData.Data.URL, nil
}

func setBrowserHeaders(req *http.Request, referer string) {
	req.Header.Set("User-Agent", getRandomUA())
	req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8")
	req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8")
	req.Header.Set("Referer", referer)
}

func setAPIHeaders(req *http.Request, referer string) {
	setBrowserHeaders(req, referer)
	req.Header.Set("Accept", "application/json, text/plain, */*")

View on GitHub (pinned to beaa561337)