#CMS Project Log Error: Not Found Issue

19 messages · Page 1 of 1 (latest)

flat slateBOT
#

people, my first CMS project in production keeps throwing this log constantly. Any idea what it could be? It’s slipping past me, and I can’t reproduce it in development: ```bash 2026-03-06T12:59:38.518397529Z [12:59:38] ERROR: Not Found
2026-03-06T12:59:38.518495729Z err: {
2026-03-06T12:59:38.518530329Z "type": "y",
2026-03-06T12:59:38.518553129Z "message": "Not Found",
2026-03-06T12:59:38.518562029Z "stack":
2026-03-06T12:59:38.518569829Z y: Not Found
2026-03-06T12:59:38.518578029Z at x (/app/.next/server/chunks/587.js:326:80845)
2026-03-06T12:59:38.518586529Z at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
2026-03-06T12:59:38.518595429Z at async /app/.next/server/chunks/8108.js:1:20787
2026-03-06T12:59:38.518619230Z at async u (/app/.next/server/chunks/6109.js:1:4403)
2026-03-06T12:59:38.518625930Z at async /app/.next/server/chunks/6109.js:1:7044
2026-03-06T12:59:38.518654430Z at async tf.do (/app/node_modules/next/dist/compiled/next-server/app-route.runtime.prod.js:18:18835)
2026-03-06T12:59:38.518661930Z at async tf.handle (/app/node_modules/next/dist/compiled/next-server/app-route.runtime.prod.js:18:23727)
2026-03-06T12:59:38.518669030Z at async doRender (/app/node_modules/next/dist/server/base-server.js:1513:42)
2026-03-06T12:59:38.518676630Z at async NextNodeServer.renderToResponseWithComponentsImpl }

supple osprey
#

are you able to share your payload.config? Or how your setting up your jobs?

plain scaffold
#

hi Sean, thanks for asking. I’ll share my entry point and how I manage the jobs. I’m happy to hear any suggestions for improvement. Thanks a lot for your interest!

#
export default buildConfig({
  serverURL:
process.env.PAYLOAD_PUBLIC_SERVER_URL || 'http://localhost:3000' || 'http://localhost:3100',
  cors: process.env.CORS_ORIGINS?.split(',') || [],
  csrf: (process.env.CSRF_ORIGINS || process.env.CORS_ORIGINS)?.split(',') || [],
  admin: adminConfig,
  routes: {
    admin: '/backdoor/admin',
    api: '/cms/api',
  },
  collections: collectionsImports,
  endpoints: customEndpoints,
  jobs: {
    tasks: [publishPromotionTask],
    autoRun: [
      {
        cron: '* * * * *', // every minute
        queue: 'default', // queues names
      },
    ],
    jobsCollectionOverrides: ({ defaultJobsCollection }) => {
      if (!defaultJobsCollection.admin) defaultJobsCollection.admin = {}
      defaultJobsCollection.admin.hidden = false
      return defaultJobsCollection
    },
  },
  graphQL: {
    disable: true,
  },
  editor: editorConfig,
  secret: process.env.PAYLOAD_SECRET || 'super-secret-key',
  typescript: tsConfig,
  db: dbConfig,
  sharp,
  plugins: pluginsImports,
})
#

My job is intended to check the promotion and publish it at a specific time. I read the documentation and I know it can be run with an external tool that calls the endpoint, but since very few promotions get published, I thought of having an automated solution, similar to Nest cron jobs

#

The job is triggered from a hook in the Promotions collection, using afterChange, to check the is_published status

#

Discord won’t let me upload my job. I’m not sure if there’s a maximum number of lines you can post, so I’ll send it as a screenshot

#
import { CollectionAfterChangeHook, PayloadRequest } from 'payload'

export const enqueuePublishPromotionHook: CollectionAfterChangeHook = async ({ doc, req }) => {
  const result = await enqueuePublishPromotion({ doc, req })
  if (result)
    console.log(`[enqueuePublishPromotionHook] Enqueued publish task for promotion ${doc.id}`)
}

export const enqueuePublishPromotion = async ({
  doc,
  req,
}: EnqueuePublishPromotionParams): Promise<boolean> => {
  if (!doc.id) return false
  if (doc.is_published) return false

  await req.payload.jobs.queue({
    task: 'publish-promotion',
    queue: 'default',
    input: {
      promotionId: doc.id,
    },
  })
  return true
}

interface EnqueuePublishPromotionParams {
  doc: { id: number; is_published: boolean }
  req: PayloadRequest
}
#

but i can write the hook afterChange

supple osprey
#

Question—in your publishPromotion task handler are you using a fetch to the REST API?

#

If the publishPromotion task is calling the Payload REST API via fetch (e.g. to update the promotion), it would need to use /cms/api/promotions/.... If it's hardcoded to the default /api/promotions/..., that route doesn't exist

plain scaffold
#

Thanks for checking it. In our case, the publishPromotion task doesn’t fetch the REST API — it uses Payload’s internal API (payload.findByID and payload.update). Also, we’ve configured routes.api as /cms/api in payload.config.ts.
So, in principle, it doesn’t look like a hardcoded /api/... route issue inside the task. In fact, in development we haven’t had any incidents either when connecting to the API or when doing updates from the frontend; if the base route were wrong, the frontend wouldn’t have been able to update promotions correctly. For now, we’re only seeing the error in production...

supple osprey
#

Ahh, I think the REST route was a red herring. So I am betting that this does actually exist in dev, but it might be logged at info level instead.

#

The NotFound is likely from: a) multiple jobs queued for the same promotion (no deduplication), where job #2 runs after job #1 already published/deleted it, OR b) the admin UI loading a completed job that was subsequently deleted

#

So adding deduplication in the hook to avoid queuing a job if one already exists for that promotionId might do the trick

plain scaffold
#

I have it blocked so that jobs don’t get deleted once they’re finished, so we can keep a more audited trail. In dev, once it’s queued I get an info log saying the promotion hasn’t been published yet, and when it gets published I also get a log saying it’s published — but that log never appears again after that. This only happens in production, which makes me curious about how I can mitigate it. What do you mean by implementing a deduplication hook? Would it also be something like afterChange?