← Back to Usage Guide Index
Quick fixes for common issues when using m7Fetch (HTTP, Specs, Modules, Batch/Sync). Use this as a first‑response playbook.
- HTTP Requests
- SpecManager
- Modules (Dynamic Imports)
- Batching & Coordination
- Auth, Cookies, and CORS
- Node / Environment
- Diagnostics & Logging Recipes
Likely cause: Server doesn’t allow your origin or headers. Fix:
- Ensure server sends
Access-Control-Allow-Originwith your app’s origin (or*without credentials). - If using cookies: also send
Access-Control-Allow-Credentials: true. - Include required
Access-Control-Allow-Headersand-Methodsfor preflights.
Likely cause: Missing credentials: "include" and/or cookie flags disallow cross‑site.
Fix:
await net.http.get("/me", { format: "full", credentials: "include" });- Server cookies must include
SameSite=None; Securefor cross‑site.
Likely cause: You set new Net({ url: "https://api.example.com" }) and called a relative path.
Fix:
- Use
absolute: truefor fully‑qualified URLs you don’t want prefixed:
await net.http.get("https://other.example.com/ping", { absolute: true });Likely cause: Wrong encoding. Fix:
- JSON: pass objects (default), or
json:trueexplicitly. - Form posts:
{ urlencoded: true }. - Files/binary: use
FormData,Blob, orArrayBuffer.
Fix: Use format: "raw" and parse manually (blob(), arrayBuffer()).
Fix:
await net.http.get("/slow", { format: "full", timeout: 5000 });Or provide/cancel your own AbortSignal.
Likely cause: Server returned HTML/error instead of JSON while json:true.
Fix: Use format:"full" and inspect status and raw body; handle non‑JSON with format:"raw" as needed.
Fix: Verify the operationId in the spec and your call. Confirm you loaded the right spec id.
Likely cause: Missing path params.
Fix:
await net.specs.call("petsAPI", "getPet", { path: { petId: "p-42" } });Fix: Add { urlencoded:true } or pass FormData/Blob explicitly according to the spec’s content type.
Fix: Load with appropriate headers/credentials:
await net.specs.load("/specs/resolve", { id:"api", headers:{ Authorization:`Bearer ${t}` }, credentials:"include", format:"full" });Likely cause: Served as non‑ESM / wrong MIME. Fix: Ensure the file is ESM and served with a JS MIME type.
Fix: Serve on same origin or enable CORS; verify path and dev‑server static roots.
Likely cause: Browser import cache.
Fix: Version the URL (/module.js?v=2) or change filename (hash).
Likely cause: Duplicate id or invalid method in loadList.
Fix: Ensure unique ids and method ∈ {get,post}.
Likely cause: Handler returned literal false (or default handler saw !res.ok).
Fix: Only return false for actual failure; wrap boolean bodies:
handler: (res) => (res.body === false ? { ok:true, body:false } : res)Likely cause: Using batchNone without storing.
Fix: Write to obj.context[id] inside your custom handler, or use batchStore/batchStatus.
Fix: Use awaitAll:false and poll sync.loaded() / sync.controller.run.
Fix: Add/refresh Authorization header or enable cookies via credentials:"include". Check token audience/scope.
Fix: Server must allow your method/headers and respond with appropriate Access-Control-* headers.
Fix: Ensure SameSite=None; Secure for cross‑site. Avoid third‑party cookie blocks in browsers by serving API on the same site when possible.
Fix: Install a WHATWG fetch polyfill (e.g., undici) and set globals:
import { fetch, Headers, Request, Response } from "undici";
Object.assign(globalThis, { fetch, Headers, Request, Response });Fix: Use ESM ("type":"module" in package.json or .mjs files). Ensure import paths point to ESM sources.
Fix: Use HTTPS for API endpoints when your app is served over HTTPS.
const r = await net.http.get("/route", { format: "full" });
console.log(r.status, r.headers, r.body);async function call(route, fn) {
try {
const res = await fn();
if (res?.ok === false) console.warn({ route, status: res.status, msg: res.body?.message });
return res;
} catch (e) {
console.error({ route, err: String(e) });
throw e;
}
}(prepend) => {
const failed = Object.keys(prepend.controller.fail);
console.warn("batch failed", failed);
}const { sync } = await net.batch.run(loadList, null, null, { awaitAll:false, limit:5 });
const total = loadList.length;
const t = setInterval(() => {
const done = Object.keys(sync.controller.run).length;
console.log(`${done}/${total}`);
if (sync.loaded()) clearInterval(t);
}, 100);- Use
format:"full"to debug status/headers/body. - Verify base URL vs
absolute:true. - Confirm CORS headers and cookie flags.
- Ensure batch
ids are unique and methods valid. - Wrap boolean
falsebodies in batch handlers. - For modules, serve ESM with correct MIME and version URLs to bust cache.
- On Node <18, polyfill
fetch.