Static files in public folder stored in kv with a hash

In short, during publish a hash is appended to assets if they’ve changed a little instead of overwriting previous asset.

What’s inside kv store: frontend.4e7d66328c.js
<script defer src="/frontend.js"></script>
stored under /public/frontend.js


bucket = './public'
entry-point = "."

worker fetch:

API.add('GET', '/*', async (req, res)=>{
  const event = new Request(req.url)
  console.log('asset', req.url)
  try {
    return await getAssetFromKV({request: event})
  } catch (e) {
    let pathname = new URL(event.request.url).pathname
    return new Response(`"${pathname}" not found`, {
      status: 404,
      statusText: "not found",


The problem here is that 404 gets returned for static assets with hash appended.

CF appends hashes to my files as well, but I don’t have any issues accessing the site files from a browser.

I’m totally shooting in the dark here, but is there a possibility for a mistake in your scripts? Here are mine (with some redactions to maintain my privacy), which do work. Perhaps you could try replacing yours with these.


account_id = "REDACTED"
name = "REDACTED"
type = "webpack"
zone_id = "REDACTED"
route = "*"
site = { bucket = "./public" }
compatibility_date = "2021-11-27"


import { getAssetFromKV, mapRequestToAsset } from '@cloudflare/kv-asset-handler'

addEventListener('fetch', event => {

async function handleEvent(event) {
    try {
        return await getAssetFromKV(event)
    } catch (e) {
        try {
            let notFoundResponse = await getAssetFromKV(event, {
                mapRequestToAsset: req => new Request(`${new URL(req.url).origin}/404.html`, req)

            return new Response(notFoundResponse.body, { ...notFoundResponse, status: 404, statusText: "Not Found" })
        } catch (e) {
            return new Response('Error 404: Page not found', { status: 404, statusText: "Not Found" })

I suppose there could be a problem with me creating a new event and not passing in mime type or something. I’ll try and add router at eventhandler to pass the real event.

What makes me thing this isn’t a coding thing is that it only doesn’t work in production, and not in miniflare/local.

I posted this on Discord yesterday but not sure you saw so I will re-post here:
The getAssetFromKV should map the asset to the hashed one.
CherryJimbo is best to answer but I can try until he’s around

What I’d recommend first is just passing in the request you’re given rather than making a new one. So, getAssetFromKV({ request: req })

I also see in the docs for kv-asset-handler it’d also like waitUntil (though not sure why exactly) so maybe try to pass that in too.

Then unrelated, your error is trying to get the request from the request. That should just be event.url (the naming for that request is definitely confusing so I’d maybe suggest renaming it too)

I’d suggest doing what I said here and then seeing if you still have issues. If you do, then post your updated code and we can go from there.

I tried replicating request completely and passing request that is heavily modified by framework. The only thing that worked was passing in the entire original event. I nested all assets in public folder inside another one so I can filter out asset calls by the nesting folder name and pathname into separate handler. (Public/assets)