{"record":{"id":"01776faab0607071","repo":"DIYgod/RSSHub","slug":"wasm-function-not-available","errorCode":null,"errorMessage":"WASM function not available","messagePattern":"WASM function not available","errorType":"exception","errorClass":null,"httpStatus":503,"severity":"error","filePath":"lib/routes/bilibili/manga-update.ts","lineNumber":47,"sourceCode":"async function genReqSign(query, body) {\n    // Don't import on top-level to avoid a cyclic dependency - wasm-exec.js generated via `pnpm build`, which in turn needs wasm-exec.js to import routes correctly\n    const { Go } = await import('./wasm-exec');\n\n    // Cache the wasm binary as it's quite large (~2MB)\n    // Here the binary is saved as base64 as the cache stores strings\n    const wasmBufferBase64 = await cache.tryGet('bilibili-manga-wasm-20250208', async () => {\n        const wasmResp = await got('https://s1.hdslb.com/bfs/manga-static/manga-pc/6732b1bf426cfc634293.wasm', {\n            responseType: 'arrayBuffer',\n        });\n        return Buffer.from(wasmResp.data).toString('base64');\n    });\n    const wasmBuffer = Buffer.from(wasmBufferBase64, 'base64');\n\n    const go = new Go();\n    const { instance } = await WebAssembly.instantiate(wasmBuffer, go.importObject);\n    go.run(instance);\n    if (void 0 === globalThis.genReqSign) {\n        throw new Error('WASM function not available');\n    }\n\n    const signature = globalThis.genReqSign(query, body, Date.now());\n\n    return signature.sign;\n}\n\nasync function handler(ctx) {\n    const comic_id = ctx.req.param('comicid').startsWith('mc') ? ctx.req.param('comicid').replace('mc', '') : ctx.req.param('comicid');\n    const link = `https://manga.bilibili.com/detail/mc${comic_id}`;\n\n    const spi_response = await got('https://api.bilibili.com/x/frontend/finger/spi');\n\n    const query = 'device=pc&platform=web&nov=25';\n    const body = JSON.stringify({\n        comic_id: Number(comic_id),\n    });\n","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/routes/bilibili/manga-update.ts#L29-L65","documentation":"Generic Error thrown by the manga-update route when the WebAssembly module fails to expose the expected genReqSign function after instantiation. The route downloads a .wasm binary from Bilibili's CDN, instantiates it via Go's WASM runtime, and checks globalThis.genReqSign. If the WASM module is corrupted, the URL is stale, or the runtime doesn't support the module, the function is undefined.","triggerScenarios":"WebAssembly.instantiate succeeds (or partially succeeds) but go.run(instance) does not register genReqSign on globalThis. Causes: the cached WASM buffer (key 'bilibili-manga-wasm-20250208') is stale/corrupted, the CDN URL returns an HTML error page instead of WASM, the Go WASM runtime version is incompatible, or Node.js lacks full WebAssembly support.","commonSituations":"Bilibili updated the WASM file (new hash/URL) but the cache key still holds the old binary; the CDN URL in the source is hardcoded and Bilibili moved the file; network proxy returned an error page that was cached as the WASM; Node.js version too old for the WASM features used.","solutions":["Clear the cached WASM: flush/clear the Redis or in-memory cache entry 'bilibili-manga-wasm-20250208' so it re-downloads.","Check if the hardcoded WASM URL (https://s1.hdslb.com/bfs/manga-static/manga-pc/6732b1bf426cfc634293.wasm) still resolves — if Bilibili changed it, update the URL and cache key in the source.","Verify the downloaded buffer is actually WASM (starts with magic bytes 0x00 0x61 0x73 0x6d) and not an HTML error page.","Ensure the Node.js version supports the WASM module (use Node 18+)."],"exampleFix":"// before: hardcoded URL and cache key that may go stale\nconst wasmResp = await got('https://s1.hdslb.com/bfs/manga-static/manga-pc/6732b1bf426cfc634293.wasm', {...});\n\n// after: validate the buffer is real WASM before instantiating\nconst wasmBuffer = Buffer.from(wasmResp.data);\nif (wasmBuffer.length < 8 || wasmBuffer[0] !== 0x00 || wasmBuffer[1] !== 0x61) {\n    throw new Error('Downloaded WASM is invalid (got non-WASM content). URL may be stale.');\n}","handlingStrategy":"validation","validationCode":"// Validate the WASM buffer before relying on it\nconst wasmBuffer = Buffer.from(wasmBufferBase64, 'base64');\nconst WASM_MAGIC = [0x00, 0x61, 0x73, 0x6d];\nconst isValidWasm = wasmBuffer.length >= 4 &&\n    WASM_MAGIC.every((byte, i) => wasmBuffer[i] === byte);\nif (!isValidWasm) {\n    throw new Error('Invalid WASM buffer — URL may be stale or CDN returned an error page');\n}","typeGuard":"function isValidWasmBuffer(buf: Buffer): boolean {\n    return buf.length >= 4 &&\n        buf[0] === 0x00 && buf[1] === 0x61 &&\n        buf[2] === 0x73 && buf[3] === 0x6d;\n}\n\nfunction isGenReqSignAvailable(): boolean {\n    return typeof globalThis.genReqSign === 'function';\n}","tryCatchPattern":"try {\n    const { instance } = await WebAssembly.instantiate(wasmBuffer, go.importObject);\n    go.run(instance);\n    if (typeof globalThis.genReqSign !== 'function') {\n        throw new Error('WASM instantiated but genReqSign not found — binary may be stale');\n    }\n} catch (e) {\n    logger.error(`WASM init failed: ${e.message}. Clearing cache.`);\n    await cache.delete?.('bilibili-manga-wasm-20250208');\n    throw e;\n}","preventionTips":["Clear the WASM cache entry when the CDN URL changes.","Validate the WASM magic bytes after download.","Update the hardcoded WASM URL when Bilibili rotates it.","Use a versioned cache key that matches the WASM file hash."],"tags":["bilibili","manga","wasm","webassembly","cache","rsshub"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}