Hello, I'm currently working on a project manageme...
# mongodb
l
Hello, I'm currently working on a project management app using Next.js, Prisma, MongoDB, and Clerk for auth. Everything is working correctly, except I get the following error any time I update an existing project, story, or task:
Error: Unauthorized
Copy code
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
    at new NodeError (node:internal/errors:371:5)
    at ServerResponse.setHeader (node:_http_outgoing:576:11)
    at NodeNextResponse.setHeader (/Users/levimason/Developer/Projects/task-app/node_modules/next/dist/server/base-http/node.js:56:19)
    at DevServer.renderError (/Users/levimason/Developer/Projects/task-app/node_modules/next/dist/server/base-server.js:1134:17)
    at DevServer.renderError (/Users/levimason/Developer/Projects/task-app/node_modules/next/dist/server/next-server.js:493:22)
    at DevServer.run (/Users/levimason/Developer/Projects/task-app/node_modules/next/dist/server/dev/next-dev-server.js:452:35)
    at async DevServer.handleRequest (/Users/levimason/Developer/Projects/task-app/node_modules/next/dist/server/base-server.js:307:20) {
  code: 'ERR_HTTP_HEADERS_SENT'
The update shows after I refresh the page. I was wondering if anyone has ran into this issue, or has any suggestion on how to resolve the error?
a
Do you have a _middleware.ts file by chance? It looks like a NextServerRequest/NextServerResponse related error Or perhaps api routes try conditionally logging (can’t send, headers already sent) wherever it is you're setting headers as a fallback Or the problem might be that it is sending the headers on every single non shallow page load—if that's the case then use the CORs middleware approach that's on the Vercel edge middleware repo examples
l
Hey Andrew, I'll look into those. I've tried logging but haven't gotten much from that. My api/tasks/[id].js looks like this for reference:
Copy code
import { requireAuth } from "@clerk/nextjs/api";
import { getTaskById, updateTask, deleteTask } from "../../../models";
import { getUserEmail } from "../../../helpers/getUserEmail";

async function handler(req, res) {
  const taskId = req.query.id;
  /** Get users email from the Clerk cookie **/
  const primaryEmail = await getUserEmail(req.session.userId);

  /** Check if the persisted task email matches the requesters **/
  const task = await getTaskById(taskId);
  if (primaryEmail !== task?.userEmail) {
    /** If it doesn't match, user will get a 401 **/
    res.status(401).end();
  }

  switch (req.method) {
    case "PUT":
      const modifiedTask = req.body;
      const updatedTask = await updateTask(taskId, modifiedTask);
      res.status(200).json(updatedTask);
      break;
    case "GET":
      res.status(200).json(task);
      break;
    case "DELETE":
      await deleteTask(taskId);
      res.status(200).json({ completed: true });
      break;
    default:
      res.status(405).end();
      break;
  }
}

export default requireAuth(handler);
and this is my updateTask hook:
Copy code
const updateTask = async function (taskId, task) {
    try {
      const response = await fetch(`/api/tasks/${taskId}`, {
        method: "PUT",
        body: JSON.stringify(task),
        headers: {
          "Content-Type": "application/json",
        },
      });
      if (!response.ok) {
        throw Error(response.statusText);
      }

      const [updatedTask] = await response.json();

      /** Find the changed task and replace it. */
      const updatedTaskIndex = task.findIndex(
        (task) => task.id === updatedTask.id
      );
      task.splice(updatedTaskIndex, 1, updatedTask);

      setTasks([...tasks]);
    } catch (err) {
      throw err;
a
hmm okay, the
getTaskById
call, can you paste that as well please? hard to say for sure with only a glimpse, if you could reproduce it in a repo (barebones, just what you're experiencing the error from) I would definitely pull it and give it a whirl also I am signed in with two different accounts to this channel (one on mobile other on laptop)...interesting
l
I'll work on getting that repo together tomorrow! Thanks for the help! Here's my
getTaskById
call in the meantime:
Copy code
export async function getTaskById(taskId) {
  return await prisma.task.findFirst({
    where: { id: taskId },
  });
}
The issue was in my api! It didn't need:
Copy code
/** Get users email from the Clerk cookie **/
  const primaryEmail = await getUserEmail(req.session.userId);

  /** Check if the persisted task email matches the requesters **/
  const task = await getTaskById(taskId);
  if (primaryEmail !== task?.userEmail) {
    /** If it doesn't match, user will get a 401 **/
    res.status(401).end();
  }
Now I'm on to solve
TypeError: Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.
During the same update action. I'm sorry for the late response.
a
hey no worries man, glad you figured it out! ah, yes, iterables looks like you're using classes since it flags a non-iterable instance? interesting way of handling that with classes https://www.typescriptlang.org/play?#code/MYGwhgzhAEDCD2BXAdgFwKYCdoEsC2ADiOnumjAJIaZgBGxAP[…]ABUAKIAJW+WVw120dwmjymMxeIXc72WFx+AFoMThkJ5MBCodZtO0gA
l
Thanks for sending that! I'll try implementing to see if that fixes it up!
🙌 1