{"record":{"id":"ac55646508f914a1","repo":"nextauthjs/next-auth","slug":"loops-send-error-json-stringify-await-res-json","errorCode":null,"errorMessage":"Loops Send Error: ${JSON.stringify(await res.json())}","messagePattern":"Loops Send Error: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/providers/loops.ts","lineNumber":74,"sourceCode":"      if (!provider.apiKey || !provider.transactionalId)\n        throw new TypeError(\"Missing Loops API Key or TransactionalId\")\n\n      const res = await fetch(\"https://app.loops.so/api/v1/transactional\", {\n        method: \"POST\",\n        headers: {\n          Authorization: `Bearer ${provider.apiKey}`,\n          \"Content-Type\": \"application/json\",\n        },\n        body: JSON.stringify({\n          transactionalId: provider.transactionalId,\n          email: to,\n          dataVariables: {\n            url: url,\n          },\n        }),\n      })\n      if (!res.ok) {\n        throw new Error(\"Loops Send Error: \" + JSON.stringify(await res.json()))\n      }\n    },\n    options: config,\n  }\n}\n","sourceCodeStart":56,"sourceCodeEnd":80,"githubUrl":"https://github.com/nextauthjs/next-auth/blob/a1a16a5a7780488c7449feece410033f445d0b31/packages/core/src/providers/loops.ts#L56-L80","documentation":"Thrown when the POST to https://app.loops.so/api/v1/transactional returns a non-OK status after credentials were present. The provider embeds the API's JSON error response in the message so you can see Loops' reason (invalid key, unknown transactionalId, missing variable, rate limit). The verification email is not sent, blocking sign-in.","triggerScenarios":"Loops transactional API rejects the request during sendVerificationRequest: expired/revoked API key, transactionalId that doesn't exist in the account, payload rejected (e.g. missing required dataVariables), or HTTP 429/5xx. Any res.ok === false triggers the throw.","commonSituations":"Using an API key from a different Loops workspace; deleting or renaming the transactional email template after deploy; malformed dataVariables not matching the template; hitting Loops rate limits during traffic spikes.","solutions":["Read the JSON error body in the message — it names the exact Loops-side problem","Verify the API key belongs to the same workspace as the transactionalId and is still active","Confirm the transactionalId matches an existing published transactional email containing the {{url}} variable","Retry with backoff if the response indicates rate limiting (429) or a 5xx"],"exampleFix":"// before\n// transactionalId from an old deleted template -> Loops returns 404\ntransactionalId: \"clx_old_id\"\n// after\n// copy the current ID from app.loops.so transactional email page\ntransactionalId: process.env.LOOPS_TRANSACTIONAL_ID,\ndataVariables: { url }, // must match template variables exactly","handlingStrategy":"try-catch","validationCode":"if (!process.env.LOOPS_API_KEY) throw new Error('LOOPS_API_KEY is required')\nif (!process.env.LOOPS_TRANSACTIONAL_ID) throw new Error('LOOPS_TRANSACTIONAL_ID is required') // must exist in your Loops workspace","typeGuard":"function isLoopsConfig(c: { apiKey?: string; transactionalId?: string }): c is { apiKey: string; transactionalId: string } {\n  return !!c.apiKey && !!c.transactionalId\n}","tryCatchPattern":"try {\n  await sendVerificationRequest(params)\n} catch (e) {\n  const msg = e instanceof Error ? e.message : String(e)\n  console.error('Loops send failed:', msg) // contains the API JSON error\n  const status = /429/.test(msg) ? 429 : undefined\n  if (status === 429) scheduleRetryWithBackoff(params)\n}","preventionTips":["Read the JSON body embedded in the error message — it names the exact Loops-side cause","Keep the transactional template and its dataVariables (url) in sync with code","Use an API key from the same workspace as the transactionalId","Add retry/backoff for 429 and 5xx responses"],"tags":["email","http-error","loops","api-error"],"backgroundTag":"email-api-http-error","analyzedSha":"a1a16a5a7780488c7449feece410033f445d0b31","analyzedAt":"2026-08-28T21:52:38.200Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}