Failed to fetch error in framework7-request when TLS certificate is invalid
0 reputation · 06 Apr 2022, 09:11 UTC
0 reputation · 06 Apr 2022, 09:11 UTC
Framework7 v8’s framework7-request wraps the browser fetch API and surfaces TLS certificate validation failures as the generic TypeError: Failed to fetch error, making it impossible to distinguish from DNS or other network problems.
Because the library forwards the rejection unchanged and does not expose the underlying AbortController or Response, developers lack a programmatic way to detect untrusted certificates in Capacitor/Cordova webviews or PWAs, especially when platform‑specific trust configuration varies.
framework7-request in hybrid or PWA contexts?31775 reputation · 06 Apr 2022, 15:54 UTC
No — you cannot currently get TLS-specific details out of framework7-request. The wrapper forwards the browser's fetch rejection unchanged, and browsers deliberately collapse certificate failures, DNS failures, and connection resets into the same opaque TypeError: Failed to fetch. This is a browser security decision (preventing pages from probing network internals), not just a Framework7 limitation. So the practical answer is: don't try to classify the error inside framework7-request — detect certificate problems one layer below or one layer above it.
Confirmed behavior: in Chromium- and WebKit-based webviews, a rejected self-signed or expired certificate surfaces to JavaScript as a plain TypeError with no distinguishing name, code, or cause. There is no DOMException with a certificate code hidden inside — the research suggestion that one exists is worth verifying in your target webview, but in current mainstream engines it does not hold. Likely explanation: because the fetch spec intentionally gives no signal, any wrapper around fetch (Framework7's included) inherits that blindness. Extending the library with error codes like certificate-invalid is therefore not feasible in pure JavaScript — the information simply never reaches the page.
Route the request through a native HTTP plugin instead of the webview's fetch. Capacitor's @capacitor/http plugin (or Cordova equivalents) performs the request in native code, where TLS errors are real, typed errors you can inspect and where certificate pinning can be configured explicitly:
import { CapacitorHttp } from '@capacitor/http';
try {
const res = await CapacitorHttp.get({ url: 'https://api.example.com/data' });
} catch (e) {
// Native layer surfaces SSL errors distinctly from connectivity errors
console.error('HTTP failed:', e);
}On Android, pair this with a network_security_config.xml that declares which domains may use your custom CA or pins, so trust decisions are explicit rather than app-wide.
You have no programmatic option — this is by design. The workable patterns are:
TypeError while navigator.onLine is true and other hosts succeed, an untrusted certificate is a strong suspect — but treat this as a heuristic, not detection.A backward-compatible enhancement is possible in shape, even if the TLS classification is limited: wrap the internal fetch call, and on rejection attach the original error plus contextual metadata (URL, timestamp, online state) to a custom error object exposed via an optional onError hook, while still throwing the original TypeError for existing callers. What you cannot honestly populate is a certificate-invalid code — mark any such mapping as unreliable across webviews until verified per-platform.
Test against a server with a self-signed certificate in your actual target webview and log the full rejection object (console.log(JSON.stringify(e, Object.getOwnPropertyNames(e)))). If you see nothing beyond the generic TypeError — which is the expected result — skip the error-classification effort and invest in the native-plugin or server-side patterns above. One detail that would change this recommendation: whether your app targets only Capacitor (native plugin is the clean fix) or must also run as a browser PWA (where heuristics and server-side checks are your only options).
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.