マルチバイト文字を含むパス、例えば /posts/[slug] のような Dynamic Routes で /posts/応援してくれた皆さんに大切なお知らせ という記事が投稿されるということはよくあることかと思います(当社調べ)。

このときに fetch ではなく unstable_cache + Prisma を使って RDBMS からデータ取得するという場合に revalidateTag を脳死で下記のように指定するとエラーとなります。

const post = (slug: string) =>
  unstable_cache(
    async () => {
      const post = await prisma.posts.findUnique(...)
      return post
    },
    [`post-${slug}`],
    { tags: ['posts', `post-${slug}`] }
  )

Vercel 上で実際に得られたエラーログはこのような感じ

 ⨯ TypeError [ERR_INVALID_CHAR]: Invalid character in header content ["x-next-cache-tags"]
    at ServerResponse.setHeader (node:_http_outgoing:651:3)
    at f.setHeader (/var/task/node_modules/next/dist/compiled/next-server/server.runtime.prod.js:16:4791)
    at J.appendHeader (/var/task/node_modules/next/dist/compiled/next-server/server.runtime.prod.js:11:28821)
    at r3.renderToResponseWithComponentsImpl (/var/task/node_modules/next/dist/compiled/next-server/server.runtime.prod.js:17:3093)
    at runNextTicks (node:internal/process/task_queues:60:5)
    at listOnTimeout (node:internal/timers:538:9)
    at process.processTimers (node:internal/timers:512:7)
    at async r3.renderPageComponent (/var/task/node_modules/next/dist/compiled/next-server/server.runtime.prod.js:17:4780)
    at async r3.renderToResponseImpl (/var/task/node_modules/next/dist/compiled/next-server/server.runtime.prod.js:17:5363)
    at async r3.pipeImpl (/var/task/node_modules/next/dist/compiled/next-server/server.runtime.prod.js:16:17297) {
  code: 'ERR_INVALID_CHAR',
  page: '/data-fetching/revalidate-tag/%E3%83%9E%E3%83%AB%E3%83%81%E3%83%90%E3%82%A4%E3%83%88%E6%96%87%E5%AD%97'
}
TypeError [ERR_INVALID_CHAR]: Invalid character in header content ["x-next-cache-tags"]
    at ServerResponse.setHeader (node:_http_outgoing:651:3)
    at f.setHeader (/var/task/node_modules/next/dist/compiled/next-server/server.runtime.prod.js:16:4791)
    at J.appendHeader (/var/task/node_modules/next/dist/compiled/next-server/server.runtime.prod.js:11:28821)
    at r3.renderToResponseWithComponentsImpl (/var/task/node_modules/next/dist/compiled/next-server/server.runtime.prod.js:17:3093)
    at runNextTicks (node:internal/process/task_queues:60:5)
    at listOnTimeout (node:internal/timers:538:9)
    at process.processTimers (node:internal/timers:512:7)
    at async r3.renderPageComponent (/var/task/node_modules/next/dist/compiled/next-server/server.runtime.prod.js:17:4780)
    at async r3.renderToResponseImpl (/var/task/node_modules/next/dist/compiled/next-server/server.runtime.prod.js:17:5363)
    at async r3.pipeImpl (/var/task/node_modules/next/dist/compiled/next-server/server.runtime.prod.js:16:17297) {
  code: 'ERR_INVALID_CHAR',
  page: '/data-fetching/revalidate-tag/%E3%83%9E%E3%83%AB%E3%83%81%E3%83%90%E3%82%A4%E3%83%88%E6%96%87%E5%AD%97'
}
Error: Runtime exited with error: exit status 1
Runtime.ExitError

ちなみにこれローカルの yarn build && yarn start では動くんですよね...

対処法として正しいかはわからないですが、下記のようなワークアラウンドで上記エラーを回避できます。

const post = (slug: string) =>
  unstable_cache(
    async () => {
      const post = await prisma.posts.findUnique(...)
      return post
    },
    [`post-${encodeURIComponent(slug)}`],
    { tags: ['posts', `post-${encodeURIComponent(slug)}`] }
  )

About

ウェブ界隈でエンジニアとして労働活動に励んでいる @gomi_ningen 個人のブログです

Copyright © 53ningen.com