DIYgod/RSSHub · error · Error

TechFlow API returned an unexpected non-JSON response.

Error message

TechFlow API returned an unexpected non-JSON response.

What it means

Thrown by techflowpost/utils.ts:91 via `throw new Error(...)` (NOT an InvalidParameterError) when the TechFlow API returns a string body that is NOT the expected Aliyun acw_sc__v2 anti-bot challenge. Flow: first request returns JSON -> return it; if it returns a string, the code assumes it is the acw_sc__v2 challenge page and looks for `var arg1='...'` to derive a cookie via getAcwScV2Cookie. If arg1 is not found, the string is some OTHER non-JSON response (error page, maintenance page, different challenge) and this error fires. A follow-up TypeError at line 97 covers the case where the retry still returns a string. The derived acwScV2Cookie is module-level and reused across calls.

Source

Thrown at lib/routes/techflowpost/utils.ts:91

    }
    return `acw_sc__v2=${getAcwScV2ByArg1(arg1)}`;
}

async function requestApi<T>(endpoint: string, referer: string, searchParams?: Record<string, string | number | boolean>) {
    const request = () =>
        got.get(`${apiRootUrl}${endpoint}`, {
            searchParams,
            headers: getHeaders(referer),
        });

    const { data } = await request();
    if (typeof data !== 'string') {
        return data as T;
    }

    const cookie = getAcwScV2Cookie(data);
    if (!cookie) {
        throw new Error('TechFlow API returned an unexpected non-JSON response.');
    }

    acwScV2Cookie = cookie;
    const retryResponse = await request();
    if (typeof retryResponse.data === 'string') {
        throw new TypeError('TechFlow API still returned an anti-crawler challenge after retry.');
    }

    return retryResponse.data as T;
}

function getPictureUrl(picture?: string) {
    if (!picture) {
        return;
    }
    return new URL(picture, uploadRootUrl).href;
}

View on GitHub (pinned to bed535e087)

Solutions

  1. Reproduce the request with the same UA/headers and inspect the raw string body to see what is actually being returned.
  2. If the challenge format changed, update getAcwScV2Cookie / getAcwScV2ByArg1 to match the new arg1 extraction and decoding.
  3. If transient (maintenance or Cloudflare burst), retry later.
  4. Confirm config.trueUA is being sent (getHeaders sets it) — a non-realistic UA often triggers a stricter challenge.

Example fix

// before
const cookie = getAcwScV2Cookie(data);
if (!cookie) {
    throw new Error('TechFlow API returned an unexpected non-JSON response.');
}
// after (surface the actual body to speed up diagnosis)
const cookie = getAcwScV2Cookie(data);
if (!cookie) {
    throw new Error(`TechFlow API returned an unexpected non-JSON response (first 200 chars): ${data.slice(0, 200)}`);
}
Defensive patterns

Strategy: retry

Validate before calling

// You cannot fully pre-validate an anti-bot challenge; sanity-check inputs instead.
// Ensure a realistic UA is sent (config.trueUA) and the referer matches the site.
function hasRealisticHeaders(headers: Record<string, string>): boolean {
  return Boolean(headers['user-agent']) && Boolean(headers['referer']);
}

Type guard

function isAcwScV2Challenge(body: string): boolean {
  return typeof body === 'string' && /var arg1='[^']*';/.test(body);
}

Try / catch

// Anti-bot failures are often transient — retry with backoff, refresh the cookie each time.
async function requestWithRetry<T>(endpoint: string, referer: string, attempts = 3): Promise<T> {
  for (let i = 0; i < attempts; i++) {
    try {
      return await requestApi<T>(endpoint, referer);
    } catch (e) {
      const last = i === attempts - 1;
      if (last || !(e instanceof Error) || !/unexpected non-JSON/i.test(e.message)) throw e;
      acwScV2Cookie = ''; // force a fresh challenge solve
      await wait(Math.pow(2, i) * 1000); // host-provided wait primitive
    }
  }
}

Prevention

When it happens

Trigger: TechFlow swaps its WAF/challenge mechanism away from acw_sc__v2; the API returns an HTML error or maintenance page; a Cloudflare interstitial is served; getAcwScV2ByArg1 (imported from ../5eplay/utils) no longer matches the site's current arg1 algorithm.

Common situations: Site provider changes anti-bot vendor; scheduled maintenance returning a static page; the acw_sc__v2 algorithm is versioned and the decoder is stale; config.trueUA not sent so a stricter challenge is returned.

Related errors


AI-assisted analysis of DIYgod/RSSHub@bed535e087 (2026-08-12). Data as JSON: /api/errors/cfd5b328ec78e8ef. Report an issue: GitHub.