{"record":{"id":"8af5783a4a722d1d","repo":"calcom/cal.diy","slug":"no-credential-found-for-user","errorCode":null,"errorMessage":"No credential found for user","messagePattern":"No credential found for user","errorType":"http","errorClass":"HttpError","httpStatus":403,"severity":"warning","filePath":"packages/app-store/basecamp3/api/projectMutation.ts","lineNumber":43,"sourceCode":"\n  const parsed = ZProjectMutationInputSchema.safeParse(req.body ?? {});\n  if (!parsed.success) {\n    throw new HttpError({\n      statusCode: 400,\n      message: \"Invalid request body\",\n    });\n  }\n  const { projectId } = parsed.data;\n\n  const { user_agent } = await getAppKeysFromSlug(\"basecamp3\");\n\n  const credential = await prisma.credential.findFirst({\n    where: { userId },\n    select: credentialForCalendarServiceSelect,\n  });\n\n  if (!credential) {\n    throw new HttpError({ statusCode: 403, message: \"No credential found for user\" });\n  }\n\n  let credentialKey = credential.key as BasecampToken;\n\n  if (credentialKey.expires_at < Date.now()) {\n    credentialKey = (await refreshAccessToken(credential)) as BasecampToken;\n  }\n\n  const basecampUserId = credentialKey.account.id;\n  const scheduleResponse = await fetch(\n    `https://3.basecampapi.com/${basecampUserId}/projects/${projectId}.json`,\n    {\n      headers: {\n        \"User-Agent\": user_agent as string,\n        Authorization: `Bearer ${credentialKey.access_token}`,\n      },\n    }\n  );","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/calcom/cal.diy/blob/176037d0afbe572f870a3c702985e7cd83fe6c0c/packages/app-store/basecamp3/api/projectMutation.ts#L25-L61","documentation":"Thrown when the authenticated user has no Basecamp 3 credential row in the DB. The mutation cannot proceed without an OAuth access token to call Basecamp. Surfaced as HTTP 403.","triggerScenarios":"User opened the Basecamp settings before completing the OAuth connect step; the credential was deleted; the request is for a different user account that never connected Basecamp.","commonSituations":"User skipped the connect step; uninstall removed the credential; multiple accounts and the active one lacks the credential.","solutions":["Complete the Basecamp 3 OAuth connect flow first so a credential row is created.","Verify a credential row exists for the user before exposing the project mutation UI.","Re-install the Basecamp 3 app if it was removed."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const credential = await prisma.credential.findFirst({\n  where: { userId },\n  select: credentialForCalendarServiceSelect,\n});\nif (!credential) {\n  // hide the project mutation UI; prompt the user to connect Basecamp first\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Complete Basecamp 3 OAuth connect before exposing project actions.","Gate the UI on the presence of a credential row.","Re-install Basecamp 3 if it was removed."],"tags":["basecamp3","credential","missing-credential","oauth"],"backgroundTag":null,"analyzedSha":"176037d0afbe572f870a3c702985e7cd83fe6c0c","analyzedAt":"2026-08-12T19:12:41.464Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}