diff --git a/webui/web/index.html b/webui/web/index.html index ecb2fbd84..0b05825fe 100644 --- a/webui/web/index.html +++ b/webui/web/index.html @@ -633,7 +633,7 @@ api.logout(); console.error('Login error:', error); - if (error.message.includes('CORS blocked')) { + if (error.message.startsWith('Network error:')) { showError(error.message); } else if (error.message.includes('Failed to fetch') || error.message.includes('NetworkError')) { showError('Unable to connect to the gateway. Please check the endpoint URL and ensure the server is running.'); diff --git a/webui/web/js/api.js b/webui/web/js/api.js index 005a7b17a..afea37ad0 100644 --- a/webui/web/js/api.js +++ b/webui/web/js/api.js @@ -717,9 +717,10 @@ class VersityAPI { signal: signal || undefined, }); } catch (e) { - // Browsers surface CORS blocks as a generic TypeError. + // Browsers surface network-level failures (CORS, TLS/certificate errors, + // unreachable host) as a generic TypeError with no further detail. if (e instanceof TypeError) { - throw new Error(`CORS blocked by gateway. Allow origin ${window.location.origin} and headers Authorization, X-Amz-Date, X-Amz-Content-Sha256, Content-Type.`); + throw new Error(`Network error: cannot reach gateway. Common causes: CORS policy (gateway must allow origin ${window.location.origin}), TLS/certificate error (untrusted or self-signed certificate rejected by the browser), or the gateway is unreachable.`); } throw e; } @@ -788,9 +789,9 @@ class VersityAPI { await this.listBucketsS3(); this.setAdminRole(false); } catch (s3Error) { - // If the gateway is reachable but the browser blocks the response due to CORS, - // surface that as an error so the UI can show a useful message. - if (s3Error && typeof s3Error.message === 'string' && s3Error.message.includes('CORS blocked')) { + // If the request failed at the network level (CORS, TLS, or unreachable), + // surface that error so the UI can show a useful diagnostic message. + if (s3Error && typeof s3Error.message === 'string' && s3Error.message.startsWith('Network error:')) { throw s3Error; } return 'none'; @@ -931,8 +932,10 @@ class VersityAPI { try { httpResponse = await fetch(presignedUrl, { method: 'GET' }); } catch (e) { + // Browsers surface network-level failures (CORS, TLS/certificate errors, + // unreachable host) as a generic TypeError with no further detail. if (e instanceof TypeError) { - throw new Error(`CORS blocked by gateway. Allow origin ${window.location.origin} for S3 responses (GET / and bucket/object operations).`); + throw new Error(`Network error: cannot reach gateway. Common causes: CORS policy (gateway must allow origin ${window.location.origin}), TLS/certificate error (untrusted or self-signed certificate rejected by the browser), or the gateway is unreachable.`); } throw e; }