ERR_HTTP2_PROTOCOL_ERROR when serving static images on netlify function

Hi there! I have recently deployed an express.js app via netlify function. There are no apparent errors in the deployment process. However, when I try to access the website, none of the statically served images are showing up. I have tested serving static files locally and everything works just fine. I am using the option to deploy directly from a github branch. When I downloaded the deployed site, all static assets are there. In fact, the site is able to serve any static HTML and CSS files just fine. It is just not working for any image files, where it always shows ERR_HTTP2_PROTOCOL_ERROR when I try to access it via google chrome.

Netlify Site name: https://master--joyful-gumdrop-f661ac.netlify.app/
Example: When I try https://master--joyful-gumdrop-f661ac.netlify.app/style.css it works just fine. However, https://master--joyful-gumdrop-f661ac.netlify.app/logo.png will throw an error, even though both file lives in the same /public folder.

I am in a bit of a time crunch to get this site released so any help would be much appreciated!

Latest deployment log:
7:20:03 PM: Starting post processing
7:20:03 PM: Skipping HTML post processing
7:20:04 PM: Post processing - header rules
7:20:04 PM: Post processing - redirect rules
7:20:04 PM: Post processing done
7:20:04 PM: Section completed: postprocessing
7:20:05 PM: Site is live :sparkles:
7:19:34 PM: build-image version: 6cae66f783f2b7ff8e3a9cdbb5031761f0b47719 (focal)
7:19:34 PM: buildbot version: 6cae66f783f2b7ff8e3a9cdbb5031761f0b47719
7:19:34 PM: Fetching cached dependencies
7:19:34 PM: Starting to download cache of 94.2MB
7:19:36 PM: Finished downloading cache in 1.405s
7:19:36 PM: Starting to extract cache
7:19:37 PM: Finished extracting cache in 760ms
7:19:37 PM: Finished fetching cache in 2.207s
7:19:37 PM: Starting to prepare the repo for build
7:19:37 PM: Preparing Git Reference refs/heads/master
7:19:38 PM: Custom build path detected. Proceeding with the specified path: ‘’
7:19:39 PM: Starting to install dependencies
7:19:39 PM: Python version set to 3.8
7:19:39 PM: Attempting Ruby version 2.7.2, read from environment
7:19:39 PM: Using Ruby version 2.7.2
7:19:40 PM: Started restoring cached go cache
7:19:40 PM: Finished restoring cached go cache
7:19:40 PM: go version go1.19.12 linux/amd64
7:19:40 PM: Using PHP version 8.0
7:19:41 PM: Started restoring cached Node.js version
7:19:42 PM: Finished restoring cached Node.js version
7:19:42 PM: v18.17.1 is already installed.
7:19:42 PM: Now using node v18.17.1 (npm v9.6.7)
7:19:43 PM: Enabling Node.js Corepack
7:19:43 PM: Started restoring cached build plugins
7:19:43 PM: Finished restoring cached build plugins
7:19:43 PM: WARNING: The environment variable ‘NODE_ENV’ is set to ‘production’. Any ‘devDependencies’ in package.json will not be installed
7:19:43 PM: Started restoring cached corepack dependencies
7:19:43 PM: Finished restoring cached corepack dependencies
7:19:43 PM: No npm workspaces detected
7:19:43 PM: Started restoring cached node modules
7:19:43 PM: Finished restoring cached node modules
7:19:43 PM: Installing npm packages using npm version 9.6.7
7:19:43 PM: up to date, audited 206 packages in 452ms
7:19:43 PM: 15 packages are looking for funding
7:19:43 PM: run npm fund for details
7:19:43 PM: found 0 vulnerabilities
7:19:43 PM: npm packages installed
7:19:44 PM: Install dependencies script success
7:19:44 PM: Starting build script
7:19:45 PM: Detected 0 framework(s)
7:19:45 PM: Section completed: initializing
7:19:46 PM: ​
7:19:46 PM: Netlify Build
7:19:46 PM: ────────────────────────────────────────────────────────────────
7:19:46 PM: ​
7:19:46 PM: ❯ Version
7:19:46 PM: @netlify/build 29.20.6
7:19:46 PM: ​
7:19:46 PM: ❯ Flags
7:19:46 PM: baseRelDir: true
7:19:46 PM: buildId: 64eab2b54647d600087c64ea
7:19:46 PM: deployId: 64eab2b54647d600087c64ec
7:19:46 PM: ​
7:19:46 PM: ❯ Current directory
7:19:46 PM: /opt/build/repo
7:19:46 PM: ​
7:19:46 PM: ❯ Config file
7:19:46 PM: /opt/build/repo/netlify.toml
7:19:46 PM: ​
7:19:46 PM: ❯ Context
7:19:46 PM: production
7:19:46 PM: ​
7:19:46 PM: Build command from Netlify app
7:19:46 PM: ────────────────────────────────────────────────────────────────
7:19:46 PM: ​
7:19:46 PM: $ npm run
7:19:47 PM: Lifecycle scripts included in albuddy-express@1.0.0:
7:19:47 PM: test
7:19:47 PM: echo Error: no test specified && exit 1
7:19:47 PM: start
7:19:47 PM: node ./netlify/functions/server.mjs
7:19:47 PM: available via npm run-script:
7:19:47 PM: dev
7:19:47 PM: nodemon ./netlify/functions/server.mjs
7:19:47 PM: ​
7:19:47 PM: (build.command completed in 207ms)
7:19:47 PM: ​
7:19:47 PM: Functions bundling
7:19:47 PM: ────────────────────────────────────────────────────────────────
7:19:47 PM: ​
7:19:47 PM: Packaging Functions from netlify/functions directory:
7:19:47 PM: - server.mjs
7:19:47 PM: ​
7:19:54 PM: ​
7:19:54 PM: (Functions bundling completed in 6.8s)
7:19:54 PM: ​
7:19:54 PM: Deploy site
7:19:54 PM: ────────────────────────────────────────────────────────────────
7:19:54 PM: ​
7:19:54 PM: Starting to deploy site from ‘’
7:19:54 PM: Calculating files to upload
7:19:54 PM: 1 new files to upload
7:19:54 PM: 1 new functions to upload
7:20:03 PM: Section completed: deploying
7:20:03 PM: Site deploy was successfully initiated
7:20:03 PM: ​
7:20:03 PM: (Deploy site completed in 9.5s)
7:20:03 PM: ​
7:20:03 PM: Netlify Build Complete
7:20:03 PM: ────────────────────────────────────────────────────────────────
7:20:03 PM: ​
7:20:03 PM: (Netlify Build completed in 17.1s)
7:20:04 PM: Caching artifacts
7:20:04 PM: Started saving node modules
7:20:04 PM: Finished saving node modules
7:20:04 PM: Started saving build plugins
7:20:04 PM: Finished saving build plugins
7:20:04 PM: Started saving corepack cache
7:20:04 PM: Finished saving corepack cache
7:20:04 PM: Started saving pip cache
7:20:04 PM: Finished saving pip cache
7:20:04 PM: Started saving emacs cask dependencies
7:20:04 PM: Finished saving emacs cask dependencies
7:20:04 PM: Started saving maven dependencies
7:20:04 PM: Finished saving maven dependencies
7:20:04 PM: Started saving boot dependencies
7:20:04 PM: Finished saving boot dependencies
7:20:04 PM: Started saving rust rustup cache
7:20:04 PM: Finished saving rust rustup cache
7:20:04 PM: Started saving go dependencies
7:20:04 PM: Finished saving go dependencies
7:20:04 PM: Build script success
7:20:04 PM: Section completed: building
7:20:04 PM: Uploading Cache of size 94.2MB
7:20:05 PM: Section completed: cleanup
7:20:05 PM: Finished processing build request in 31.067s

Hi @JackZiyangChen,

Thank you for reaching out and welcome to the Netlify support forums!

I’m seeing errors in the dev console:

Going to https://cdn.jsdelivr.net/npm/heroicons@4.3.0/dist/heroicons.min.css I see Couldn't find the requested release version 4.3.0.

That url doesn’t appear to be correct.

For the images, you’ll want to ensure that the paths are correct.

Also, are you using a framework?

Hi thanks for getting back to me. All the 404 and 403 errors are expected. They are issues on my end and I will fix them. I am more concerned about the HTTP2_PROTOCOL_ERROR displayed here. The path for image is definitely correct, since they live under the same directory (/public) as style.css and I have had no problems loading style.css. It appears that the protocol error only happens when I try to load image files.

Here’s what the directory looks like:

I am using Express.js framework.

Have you checked: Express on Netlify | Netlify Docs?

Yes I have, step by step. Here’s what my netlify.toml looks like

[functions]
  external_node_modules = ["express"]
  node_bundler = "esbuild"
  included_files = ["**/*"]
[[redirects]]
  force = true
  from = "/*"
  status = 200
  to = "/.netlify/functions/server/:splat"

The routing clearly works. All HTML and CSS are served correctly. The only error I encountered is when I try to access image static content.

To provide more context, here is my full directory

And here’s my server.mjs

Why do you wish to setup static files through Express? You’re simply wasting your Function invocations and incurring costs where they’re not needed. Not to mention, you’re making your site slower. You should let Netlify serve the static files and only invoke your Function for the paths that need the Function. For example, if you remove force=true from your toml, you’d be able to access the images directly at https://joyful-gumdrop-f661ac.netlify.app/public/logo.png. In your current setup, you’re going to incur Function bills very quickly.

I see. I was not aware of that and I will take the approach you mentioned then. It seems like setting force=false and letting netlify serve the static content solve the problem. Thanks for the help.