Tencent/WeKnora · error

state=done but no jsonUrl

Error message

state=done but no jsonUrl

What it means

pollJob in the PaddleOCR VL cloud converter polls the remote parsing task and, when the API reports state="done", expects a result JSONURL in the response. This error is thrown when the provider marks the task done but omits ResultURL.JSONURL, so the converter has no result to download. It is a defensive guard against a malformed/incomplete provider success response rather than a local bug.

Source

Thrown at internal/infrastructure/docparser/paddleocr_vl_cloud_converter.go:238

		}

		var pollResp paddleOCRVLCloudPollResponse
		if err := json.Unmarshal(respBody, &pollResp); err != nil {
			logger.Errorf(context.Background(), "[PaddleOCR-VL Cloud] poll #%d decode error: %v", pollCount, err)
			sleepCtx(ctx, paddleOCRVLCloudPollInterval)
			continue
		}

		state := strings.ToLower(pollResp.Data.State)
		if pollCount == 1 || pollCount%6 == 0 || state == "done" || state == "failed" {
			logger.Infof(context.Background(), "[PaddleOCR-VL Cloud] poll #%d: state=%s pages=%d/%d",
				pollCount, state, pollResp.Data.ExtractProgress.ExtractedPages, pollResp.Data.ExtractProgress.TotalPages)
		}

		switch state {
		case "done":
			if pollResp.Data.ResultURL.JSONURL == "" {
				return "", fmt.Errorf("state=done but no jsonUrl")
			}
			return pollResp.Data.ResultURL.JSONURL, nil
		case "failed":
			return "", fmt.Errorf("task failed: %s", pollResp.Data.ErrorMsg)
		}

		sleepCtx(ctx, paddleOCRVLCloudPollInterval)
	}

	return "", fmt.Errorf("task timed out after %d polls", pollCount)
}

// --- result parsing ---

type paddleOCRVLCloudResultLine struct {
	Result struct {
		LayoutParsingResults []struct {
			Markdown struct {

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Retry Read once or twice — transient provider inconsistency often resolves on a subsequent task submission.
  2. Log the full raw poll response body to confirm the JSONURL field path and whether the API contract changed.
  3. Check the provider's API docs/changelog for a renamed result field (e.g. resultUrl vs resultURL) and update the response struct JSON tags.
  4. Verify the account/plan still has quota and that result artifacts are not being purged by the provider.
  5. If persistent, treat the task as failed and resubmit the document, or fall back to a local parser.

Example fix

// before
resultURL, err := reader.Read(ctx, file)
if err != nil {
    return err // state=done but no jsonUrl
}

// after
resultURL, err := reader.Read(ctx, file)
if err != nil {
    if strings.Contains(err.Error(), "no jsonUrl") {
        resultURL, err = reader.Read(ctx, file) // retry transient provider glitch
    }
    if err != nil {
        return fmt.Errorf("paddleocr cloud parse: %w", err)
    }
}
Defensive patterns

Strategy: retry

Validate before calling

// before calling Read, ensure the provider result contract is current
// (field-level validation happens server-side; here we guard the caller)
if reader == nil {
    return errors.New("paddleocr cloud reader not configured")
}

Try / catch

url, err := reader.Read(ctx, file)
if err != nil && strings.Contains(err.Error(), "no jsonUrl") {
    url, err = reader.Read(ctx, file) // one retry for provider glitch
}
if err != nil { return err }

Prevention

When it happens

Trigger: pollJob receives a poll response whose data.state is "done" while pollResp.Data.ResultURL.JSONURL is the empty string; called from Read after submitting a document for cloud parsing.

Common situations: Provider-side anomalies: the OCR task finished but result generation/upload failed silently; an API version change renamed or moved the result-URL field; a proxy or gateway stripped the JSON body; expired/limited account where the platform drops result artifacts but still flips state to done.

Related errors


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/e8023b6f3d8b9d9c. Report an issue: GitHub.