Skip to content

fix(next/font/google): bound Google Fonts fetch timeout on Turbopack#95981

Merged
aurorascharff merged 10 commits into
canaryfrom
aurorascharff/font-google-fetch-timeout
Jul 23, 2026
Merged

fix(next/font/google): bound Google Fonts fetch timeout on Turbopack#95981
aurorascharff merged 10 commits into
canaryfrom
aurorascharff/font-google-fetch-timeout

Conversation

@aurorascharff

@aurorascharff aurorascharff commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

What?

Bound the compile-time Google Fonts fetch on the Turbopack path so next dev / next build can't hang forever on a stuck network.

Why?

next/font/google fetches from Google Fonts at compile time. When the connection hangs (captive portal, packet-dropping proxy, broken IPv6), the fetch had no timeout, so compilation blocked until the OS connect timeout (~75s) or indefinitely.

How?

  • FetchClientConfig gets a connect_timeout (10s) and total timeout (60s); Google Fonts overrides them to 5s / 30s.
  • Transient failures retry up to 3×, each attempt its own duration_span!.
  • On failure: next build errors (fails the build), next dev warns and uses the fallback font. Both messages report the attempt count and suggest next/font/local.

Follow-ups

  • Reduce the dev-mode timeout (build keeps the longer value).
  • Port the fix to the webpack/JS path (packages/font/src/google).

Related: #92301. #76473.

@github-actions

github-actions Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Stats from current PR

🟢 1 improvement

Metric Canary PR Change Trend
Turbo Build Time (cached) 5.498s 5.195s 🟢 303ms (-6%) ▁█▃▁▁
📊 All Metrics
📖 Metrics Glossary

Dev Server Metrics:

  • Listen = TCP port starts accepting connections
  • First Request = HTTP server returns successful response
  • Cold = Fresh build (no cache)
  • Warm = With cached build artifacts

Build Metrics:

  • Fresh = Clean build (no .next directory)
  • Cached = With existing .next directory

Change Thresholds:

  • Time: Changes < 50ms AND < 10%, OR < 2% are insignificant
  • Size: Changes < 1KB AND < 1% are insignificant
  • All other changes are flagged to catch regressions

⚡ Dev Server

Metric Canary PR Change Trend
Cold (Listen) 813ms 813ms ▁█▂▂▁
Cold (Ready in log) 786ms 784ms ▁█▂▁▁
Cold (First Request) 1.330s 1.305s ▁█▃▁▁
Warm (Listen) 813ms 812ms ▁█▂▁▁
Warm (Ready in log) 795ms 778ms ▁█▂▁▁
Warm (First Request) 1.330s 1.292s ▁█▂▁▁
📦 Dev Server (Webpack) (Legacy)

📦 Dev Server (Webpack)

Metric Canary PR Change Trend
Cold (Listen) 812ms 813ms ▂▂▁▂▂
Cold (Ready in log) 787ms 778ms ▁▁▁▁▁
Cold (First Request) 3.421s 3.369s ▃▂▁▃▂
Warm (Listen) 812ms 814ms ▂▂▂▂▂
Warm (Ready in log) 787ms 788ms ▁▁▁▁▁
Warm (First Request) 3.419s 3.457s ▃▁▁▄▁

⚡ Production Builds

Metric Canary PR Change Trend
Fresh Build 5.298s 5.122s ▁█▄▁▁
Cached Build 5.498s 5.195s 🟢 303ms (-6%) ▁█▃▁▁
📦 Production Builds (Webpack) (Legacy)

📦 Production Builds (Webpack)

Metric Canary PR Change Trend
Fresh Build 25.932s 25.695s ▁▁▁▁▁
Cached Build 26.211s 26.084s ▁▂▁▁▁
node_modules Size 527 MB 527 MB ▁▁▁██
📦 Bundle Sizes

Bundle Sizes

⚡ Turbopack

Client

Main Bundles
Canary PR Change
00v6npozcc3c3.js gzip 155 B N/A -
0a-p0meqxynjz.js gzip 10.3 kB N/A -
0avtke4yefj4-.js gzip 13.1 kB N/A -
0cz1d0mv5g_q7.js gzip 39.4 kB 39.4 kB
0nvyq--brb2d1.js gzip 71.1 kB N/A -
0pt5of3ch6d2u.js gzip 13.6 kB N/A -
0xnsdo-6y9r3k.js gzip 5.72 kB N/A -
0yi7is8u4covm.js gzip 8.77 kB N/A -
1aqu9ze6v_-92.js gzip 157 B N/A -
1bhefyyiiy1a1.js gzip 160 B N/A -
1elt1qium-r2m.css gzip 115 B 115 B
1lh1fi2q329kp.js gzip 155 B N/A -
1lsl-hvtjoz38.js gzip 7.4 kB N/A -
1ltc02dslhmu0.js gzip 156 B N/A -
1prv-wg6jgtt2.js gzip 8.77 kB N/A -
1t47vod02e_4a.js gzip 8.75 kB N/A -
1tbq0-klq39t1.js gzip 156 B N/A -
1tf1phijqlx9j.js gzip 220 B 220 B
1tw002sq5bo4l.js gzip 10 kB N/A -
1wlerik1n7zbr.js gzip 8.7 kB N/A -
22vemgj_ppw9g.js gzip 157 B N/A -
28koph4jjzmen.js gzip 45.2 kB N/A -
2lviwqiqxm904.js gzip 3.52 kB N/A -
2pevdqjpbf3xk.js gzip 9.45 kB N/A -
2ppm-9338hg-g.js gzip 155 B N/A -
2qd2anu9eizlz.js gzip 8.75 kB N/A -
2sv39ae5_8vfj.js gzip 8.81 kB N/A -
2utx6n7w65xqa.js gzip 8.7 kB N/A -
2vo_g-1nu597x.js gzip 153 B N/A -
3_gkkw57bfro8.js gzip 168 B N/A -
3-ukivglqkfeq.js gzip 8.78 kB N/A -
325xisqrylugu.js gzip 450 B N/A -
3e9jui3nrs0cq.js gzip 161 B N/A -
3jc9ghvds1spf.js gzip 2.29 kB N/A -
3juwkvkgvywfe.js gzip 10.6 kB N/A -
3kbove7q58uqh.js gzip 13.2 kB N/A -
3qn7vntp30gaj.js gzip 1.47 kB N/A -
3tg5xymt-y3pf.js gzip 157 B N/A -
3y5l7macq6332.js gzip 156 B N/A -
45bnqre7r-j34.js gzip 65.6 kB N/A -
turbopack-0d..qkmb.js gzip 3.81 kB N/A -
turbopack-0m..pdb9.js gzip 3.78 kB N/A -
turbopack-1-..1ho9.js gzip 3.8 kB N/A -
turbopack-1d..316h.js gzip 3.82 kB N/A -
turbopack-1w..lyf1.js gzip 3.81 kB N/A -
turbopack-25..qyhv.js gzip 3.81 kB N/A -
turbopack-2c..lyeg.js gzip 3.81 kB N/A -
turbopack-2h..a-uq.js gzip 3.8 kB N/A -
turbopack-2j..bz11.js gzip 3.81 kB N/A -
turbopack-3-..gj1l.js gzip 3.81 kB N/A -
turbopack-36..evj4.js gzip 3.81 kB N/A -
turbopack-37.._yox.js gzip 3.8 kB N/A -
turbopack-3p..5n5c.js gzip 3.81 kB N/A -
turbopack-41..w-sa.js gzip 3.81 kB N/A -
030a1njeh5b77.js gzip N/A 10 kB -
0g4_k2uc6wv4q.js gzip N/A 157 B -
0gks75us8x8np.js gzip N/A 156 B -
0ot0qt5np20h7.js gzip N/A 8.78 kB -
1_0n9btq9p4ce.js gzip N/A 156 B -
1-qxxhh8-axib.js gzip N/A 45.2 kB -
12km8nr29deej.js gzip N/A 152 B -
12m9rr7_7cexd.js gzip N/A 8.7 kB -
186r3y_rfvr0b.js gzip N/A 8.78 kB -
19v97848yrjp7.js gzip N/A 8.81 kB -
1em_c2iwtphkh.js gzip N/A 155 B -
1j9dy_1o47w3f.js gzip N/A 157 B -
1k4eu86-nhh6g.js gzip N/A 156 B -
1nd_0rwgz2ozk.js gzip N/A 9.45 kB -
1oi9pltr_e10m.js gzip N/A 10.6 kB -
1rd9tzqgzsz2w.js gzip N/A 8.77 kB -
1rq1g_cwv642d.js gzip N/A 10.3 kB -
1sek4rdapnadp.js gzip N/A 157 B -
1uojw_uabeg93.js gzip N/A 450 B -
1w-7lusgyl81y.js gzip N/A 8.7 kB -
2-kdoq-jy_crq.js gzip N/A 7.41 kB -
21h56wdn9zddo.js gzip N/A 8.75 kB -
23m4n1cp16_my.js gzip N/A 158 B -
26urb3nj-ua41.js gzip N/A 71.1 kB -
2caur9q46_a46.js gzip N/A 160 B -
2d_gfdd2kvo3j.js gzip N/A 155 B -
2lg10omv7xu14.js gzip N/A 3.52 kB -
2ovff1533zvno.js gzip N/A 13.2 kB -
2s4z8jy0z7v93.js gzip N/A 1.46 kB -
2y6gb5bs4mnam.js gzip N/A 8.75 kB -
341h71ln1jpl3.js gzip N/A 2.29 kB -
34ttpt_n7605h.js gzip N/A 5.72 kB -
36ckfq9o-ys-a.js gzip N/A 13.1 kB -
3djafohg3a3jg.js gzip N/A 161 B -
3vdh6_u50pu5t.js gzip N/A 13.6 kB -
3vughx3b6vlec.js gzip N/A 65.6 kB -
3yr5uv4qtknye.js gzip N/A 169 B -
turbopack-04..uq8-.js gzip N/A 3.78 kB -
turbopack-0q..2a0a.js gzip N/A 3.81 kB -
turbopack-0w..pdzm.js gzip N/A 3.81 kB -
turbopack-1_..muub.js gzip N/A 3.8 kB -
turbopack-1d..c7mz.js gzip N/A 3.8 kB -
turbopack-1j..b3jd.js gzip N/A 3.81 kB -
turbopack-1s..sjan.js gzip N/A 3.81 kB -
turbopack-2b..8l3_.js gzip N/A 3.8 kB -
turbopack-2q..n442.js gzip N/A 3.81 kB -
turbopack-2t..t3xp.js gzip N/A 3.82 kB -
turbopack-2z..c636.js gzip N/A 3.8 kB -
turbopack-3_..zctb.js gzip N/A 3.8 kB -
turbopack-39.._x1-.js gzip N/A 3.81 kB -
turbopack-3e..733c.js gzip N/A 3.81 kB -
Total 448 kB 448 kB ⚠️ +37 B

Server

Middleware
Canary PR Change
middleware-b..fest.js gzip 780 B 778 B
Total 780 B 778 B ✅ -2 B
Build Details
Build Manifests
Canary PR Change
_buildManifest.js gzip 433 B 431 B
Total 433 B 431 B ✅ -2 B

📦 Webpack

Client

Main Bundles
Canary PR Change
3322-HASH.js gzip 63.7 kB N/A -
4191.HASH.js gzip 169 B N/A -
7920-HASH.js gzip 4.68 kB N/A -
9784-HASH.js gzip 5.63 kB N/A -
b1ad9f4c-HASH.js gzip 62.9 kB N/A -
framework-HASH.js gzip 59.7 kB 59.7 kB
main-app-HASH.js gzip 251 B 253 B
main-HASH.js gzip 40 kB 40 kB
webpack-HASH.js gzip 1.68 kB 1.68 kB
3577.HASH.js gzip N/A 168 B -
578-HASH.js gzip N/A 64.4 kB -
8590-HASH.js gzip N/A 5.61 kB -
9750-HASH.js gzip N/A 4.69 kB -
a8984546-HASH.js gzip N/A 62.9 kB -
Total 239 kB 239 kB ⚠️ +639 B
Polyfills
Canary PR Change
polyfills-HASH.js gzip 39.4 kB 39.4 kB
Total 39.4 kB 39.4 kB
Pages
Canary PR Change
_app-HASH.js gzip 194 B 193 B
_error-HASH.js gzip 181 B 182 B
css-HASH.js gzip 334 B 331 B
dynamic-HASH.js gzip 1.81 kB 1.81 kB
edge-ssr-HASH.js gzip 255 B 253 B
head-HASH.js gzip 349 B 351 B
hooks-HASH.js gzip 382 B 384 B
image-HASH.js gzip 581 B 582 B
index-HASH.js gzip 260 B 259 B
link-HASH.js gzip 2.48 kB 2.48 kB
routerDirect..HASH.js gzip 317 B 318 B
script-HASH.js gzip 384 B 386 B
withRouter-HASH.js gzip 316 B 315 B
1afbb74e6ecf..834.css gzip 106 B 106 B
Total 7.95 kB 7.95 kB ⚠️ +1 B

Server

Edge SSR
Canary PR Change
edge-ssr.js gzip 128 kB 128 kB
page.js gzip 287 kB 287 kB
Total 415 kB 414 kB ✅ -938 B
Middleware
Canary PR Change
middleware-b..fest.js gzip 618 B 616 B
middleware-r..fest.js gzip 156 B 156 B
middleware.js gzip 45.3 kB 45.1 kB
edge-runtime..pack.js gzip 842 B 842 B
Total 46.9 kB 46.8 kB ✅ -126 B
Build Details
Build Manifests
Canary PR Change
_buildManifest.js gzip 718 B 718 B
Total 718 B 718 B
Build Cache
Canary PR Change
0.pack gzip 4.84 MB 4.83 MB 🟢 6.85 kB (0%)
index.pack gzip 120 kB 119 kB
index.pack.old gzip 121 kB 120 kB
Total 5.08 MB 5.07 MB ✅ -9.09 kB

🔄 Shared (bundler-independent)

Runtimes
Canary PR Change
app-page-exp...dev.js gzip 366 kB 366 kB
app-page-exp..prod.js gzip 202 kB 202 kB
app-page-tur...dev.js gzip 365 kB 365 kB
app-page-tur..prod.js gzip 202 kB 202 kB
app-page-tur...dev.js gzip 362 kB 362 kB
app-page-tur..prod.js gzip 200 kB 200 kB
app-page.run...dev.js gzip 362 kB 362 kB
app-page.run..prod.js gzip 200 kB 200 kB
app-route-ex...dev.js gzip 81.8 kB 81.8 kB
app-route-ex..prod.js gzip 55.6 kB 55.6 kB
app-route-tu...dev.js gzip 81.8 kB 81.8 kB
app-route-tu..prod.js gzip 55.6 kB 55.6 kB
app-route-tu...dev.js gzip 81.4 kB 81.4 kB
app-route-tu..prod.js gzip 55.4 kB 55.4 kB
app-route.ru...dev.js gzip 81.4 kB 81.4 kB
app-route.ru..prod.js gzip 55.4 kB 55.4 kB
dist_client_...dev.js gzip 324 B 324 B
dist_client_...dev.js gzip 326 B 326 B
dist_client_...dev.js gzip 318 B 318 B
dist_client_...dev.js gzip 317 B 317 B
pages-api-tu...dev.js gzip 45.4 kB 45.4 kB
pages-api-tu..prod.js gzip 34.1 kB 34.1 kB
pages-api.ru...dev.js gzip 45.4 kB 45.4 kB
pages-api.ru..prod.js gzip 34.1 kB 34.1 kB
pages-turbo....dev.js gzip 54.9 kB 54.9 kB
pages-turbo...prod.js gzip 39.7 kB 39.7 kB
pages.runtim...dev.js gzip 54.8 kB 54.8 kB
pages.runtim..prod.js gzip 39.7 kB 39.7 kB
server.runti..prod.js gzip 67.8 kB 67.8 kB
use-cache-pr...dev.js gzip 71.6 kB 71.6 kB
use-cache-pr...dev.js gzip 71.6 kB 71.6 kB
use-cache-pr...dev.js gzip 69.9 kB 69.9 kB
use-cache-pr...dev.js gzip 69.9 kB 69.9 kB
Total 3.51 MB 3.51 MB
📎 Tarball URL
https://vercel-packages.vercel.app/next/commits/d5ac23c735121eb3e6a55eb2c0de065a9ba80fe3/next

Commit: d5ac23c

@github-actions

github-actions Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Tests Passed

Commit: d5ac23c

@aurorascharff
aurorascharff marked this pull request as ready for review July 20, 2026 19:53
Copilot AI review requested due to automatic review settings July 20, 2026 19:53
@aurorascharff
aurorascharff marked this pull request as draft July 20, 2026 19:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves the compile-time Google Fonts download path in next/font/google to avoid indefinite hangs on “stuck” networks and to make retry behavior visible in build/dev output.

Changes:

  • Bound fetchResource() request timeouts in both dev and build (3s / 6s) so compilation can’t hang forever.
  • Switched retry logging to Next’s standard build logger to ensure retry attempts are visible (especially under Turbopack).
  • Added targeted Jest coverage for retry logging, request timeouts, and dev/build fallback behavior; fixed a stray brace in the dev fallback error message.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/font/src/google/retry.ts Logs retry attempts via next/dist/build/output/log instead of console.error.
packages/font/src/google/retry.test.ts Adds unit coverage for retry logging and retry limit behavior.
packages/font/src/google/loader.ts Fixes dev fallback error message formatting (removes stray }).
packages/font/src/google/loader.test.ts Adds coverage for dev fallback logging and build-time failure behavior when Google Fonts is unreachable.
packages/font/src/google/fetch-resource.ts Ensures a timeout is always applied (3s dev / 6s build).
packages/font/src/google/fetch-resource.test.ts Adds coverage ensuring hanging connections time out in both dev and build modes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/font/src/google/retry.ts Outdated
Comment thread packages/font/src/google/fetch-resource.test.ts Outdated
@aurorascharff aurorascharff changed the title fix(next/font/google): bound fetch timeout and surface retries fix(next/font/google): bound Google Fonts fetch timeout (webpack + Turbopack) Jul 20, 2026

@vercel vercel Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Suggestion:

Test struct literal for FetchClientConfig omits the newly-required connect_timeout field, causing a compilation failure of the turbo-tasks-fetch test crate.

Fix on Vercel

@aurorascharff
aurorascharff marked this pull request as ready for review July 20, 2026 20:41
Comment thread packages/font/src/google/fetch-resource.ts Outdated
Comment thread packages/font/src/google/loader.test.ts Outdated
Comment thread turbopack/crates/turbo-tasks-fetch/src/client.rs Outdated
Comment thread turbopack/crates/turbo-tasks-fetch/src/client.rs Outdated
Comment thread turbopack/crates/turbo-tasks-fetch/src/client.rs Outdated
Comment thread turbopack/crates/turbo-tasks-fetch/src/client.rs Outdated
@aurorascharff
aurorascharff marked this pull request as draft July 21, 2026 08:04
@aurorascharff
aurorascharff force-pushed the aurorascharff/font-google-fetch-timeout branch from 9ae296d to 5274cd8 Compare July 22, 2026 12:59
@aurorascharff aurorascharff changed the title fix(next/font/google): bound Google Fonts fetch timeout (webpack + Turbopack) fix(next/font/google): bound Google Fonts fetch timeout on Turbopack Jul 22, 2026
@aurorascharff
aurorascharff marked this pull request as ready for review July 22, 2026 13:26
@aurorascharff
aurorascharff force-pushed the aurorascharff/font-google-fetch-timeout branch from 5274cd8 to 5fa8d1e Compare July 22, 2026 13:44
next/font/google downloads font CSS/files from Google Fonts at compile
time. On a "stuck" network (captive portal, hanging corporate proxy,
blocked endpoint) the TCP/proxy connect never completes, so `next dev`
and `next build` hang until the OS connect timeout (~75s) or forever.

Bound the fetch on the Turbopack path:
- Add `connect_timeout` (default 10s) and `timeout` (default 60s) to
  `FetchClientConfig`; the generic crate keeps generous defaults.
- Override for Google Fonts: 5s connect / 30s total, one value that
  works for both dev and build.
- Retry transient failures (connect/timeout/request) up to
  `MAX_FETCH_RETRIES` times, each attempt wrapped in a `duration_span!`
  so retries are visible in the trace viewer.
- Enrich the terminal-visible font Issue to say the download failed
  after N attempts and to recommend self-hosting with `next/font/local`.

On `next build` an unreachable font still fails the build (now promptly),
and `next dev` falls back to the metric-adjusted fallback font.
The Turbopack path now emits an enriched message (retry count + self-host
hint); the webpack/JS path keeps the original wording. Assert per bundler
so both matrices pass.
@aurorascharff
aurorascharff force-pushed the aurorascharff/font-google-fetch-timeout branch from 11152f1 to 9c3a1c9 Compare July 22, 2026 15:35
Comment thread crates/next-core/src/next_config.rs Outdated
Comment thread turbopack/crates/turbo-tasks-fetch/src/client.rs Outdated
Comment thread turbopack/crates/turbo-tasks-fetch/src/client.rs Outdated
Comment thread crates/next-core/src/next_config.rs Outdated
Comment thread crates/next-core/src/next_config.rs Outdated
Comment thread crates/next-core/src/next_font/google/mod.rs Outdated
Comment thread crates/next-core/src/next_font/google/mod.rs Outdated
Comment thread turbopack/crates/turbo-tasks-fetch/src/client.rs Outdated
Comment thread test/e2e/next-font/google-fetch-error.test.ts Outdated
Comment thread crates/next-core/src/next_config.rs Outdated
aurorascharff and others added 5 commits July 22, 2026 19:51
Co-authored-by: Benjamin Woodruff <benjamin.woodruff@vercel.com>
Co-authored-by: Benjamin Woodruff <benjamin.woodruff@vercel.com>
Co-authored-by: Benjamin Woodruff <benjamin.woodruff@vercel.com>
Co-authored-by: Benjamin Woodruff <benjamin.woodruff@vercel.com>
Co-authored-by: Benjamin Woodruff <benjamin.woodruff@vercel.com>
Comment thread crates/next-core/src/next_config.rs Outdated
Address review:
- Move the retry count into `FetchClientConfig.max_retries` (default 0, generic);
  Google Fonts opts into 3.
- Also retry 5xx responses, not just connect/timeout/request errors.
- Add the `std::time::Duration` import the accepted timeout suggestion needed
  (the branch didn't compile without it).
…edString

Address review:
- Dedicated GoogleFontsFetchIssue that generates its title/description lazily
  in the trait impl instead of storing pre-built StyledStrings.
- Compose StyledString::Line/Code/Stack instead of format! + interpolation and
  `\n` in a single Text.
- Share the description between dev and build (severity drives the difference).
- Mention configuring HTTP_PROXY/HTTPS_PROXY in the guidance.

Update the e2e assertions: Turbopack now renders the font name via
StyledString::Code (no backticks); the webpack/JS path is unchanged.
@aurorascharff
aurorascharff requested a review from bgw July 22, 2026 20:27

@bgw bgw left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for doing this @aurorascharff

Comment on lines +51 to +108
impl Issue for GoogleFontsFetchIssue {
fn stage(&self) -> IssueStage {
IssueStage::Resolve
}

fn severity(&self) -> IssueSeverity {
if self.is_dev {
IssueSeverity::Warning
} else {
IssueSeverity::Error
}
}

async fn file_path(&self) -> Result<FileSystemPath> {
Ok(self.path.clone())
}

async fn title(&self) -> Result<StyledString> {
Ok(StyledString::Line(vec![
StyledString::Code(rcstr!("next/font:")),
StyledString::Text(if self.is_dev {
rcstr!(" warning:")
} else {
rcstr!(" error:")
}),
]))
}

async fn description(&self) -> Result<Option<StyledString>> {
let summary = if self.is_dev {
StyledString::Line(vec![
StyledString::Text(rcstr!("Failed to download ")),
StyledString::Code(self.font_family.clone()),
StyledString::Text(rcstr!(" from Google Fonts. Using a fallback font instead.")),
])
} else {
StyledString::Line(vec![
StyledString::Text(rcstr!("Failed to fetch ")),
StyledString::Code(self.font_family.clone()),
StyledString::Text(rcstr!(" from Google Fonts.")),
])
};
let guidance = StyledString::Line(vec![
StyledString::Text(rcstr!(
"If you are offline or behind a proxy, self-host the font with "
)),
StyledString::Code(rcstr!("next/font/local")),
StyledString::Text(rcstr!(", or set ")),
StyledString::Code(rcstr!("HTTP_PROXY")),
StyledString::Text(rcstr!("/")),
StyledString::Code(rcstr!("HTTPS_PROXY")),
StyledString::Text(rcstr!(" so Next.js can reach ")),
StyledString::Code(rcstr!("fonts.googleapis.com")),
StyledString::Text(rcstr!(".")),
]);
Ok(Some(StyledString::Stack(vec![summary, guidance])))
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome. This is much nicer, thanks.

Comment on lines +2709 to +2715
// Bounds the Google Fonts fetch. Dev fails fast and falls back to a system font;
// build tolerates a slower network since a missing font fails the build.
let (connect_timeout, timeout) = if matches!(*next_mode.await?, NextMode::Development) {
(Duration::from_secs(5), Duration::from_secs(10))
} else {
(Duration::from_secs(10), Duration::from_secs(30))
};

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@aurorascharff
aurorascharff merged commit aa4f46a into canary Jul 23, 2026
426 of 432 checks passed
@aurorascharff
aurorascharff deleted the aurorascharff/font-google-fetch-timeout branch July 23, 2026 15:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants