nextauthjs/next-auth · error

Account not created

Error message

Account not created

What it means

linkAccount() creates an account document linking an OAuth provider identity to a user. If the SurrealDB create throws, or the returned array is empty, the adapter discards the underlying error and throws 'Account not created'.

Source

Thrown at packages/adapter-surrealdb/src/index.ts:309

      } catch {}

      // delete user
      await surreal.delete(new RecordId("user", userId))

      // TODO: put all 3 deletes inside a Promise all
    },
    async linkAccount(account: AdapterAccount) {
      try {
        const surreal = await client
        const accountDoc = await surreal.create<
          AccountDoc,
          Omit<AccountDoc, "id">
        >("account", accountToDoc(account))
        if (accountDoc.length) {
          return docToAccount(accountDoc[0])
        }
      } catch {}
      throw new Error("Account not created")
    },
    async unlinkAccount({
      providerAccountId,
      provider,
    }: Pick<AdapterAccount, "provider" | "providerAccountId">) {
      const surreal = await client
      try {
        const [accounts] = await surreal.query<[AccountDoc[]]>(
          `SELECT * FROM account WHERE providerAccountId = $providerAccountId AND provider = $provider LIMIT 1`,
          { providerAccountId, provider }
        )
        const account = accounts.at(0)
        if (account) {
          await surreal.delete(account.id)
        }
      } catch {}
    },
    async createSession({

View on GitHub (pinned to a1a16a5a77)

Solutions

  1. Check SurrealDB connectivity and that the `account` table exists and is writable by the adapter user
  2. Inspect SurrealDB permissions/DEFINE TABLE PERMISSIONS so the adapter role can CREATE on account
  3. Look for an existing account row with the same provider + providerAccountId (duplicate link attempt)
  4. Add temporary logging inside the try to expose the swallowed error

Example fix

// before
await adapter.linkAccount(account) // throws 'Account not created'
// after
const existing = await adapter.getAccount(account.providerAccountId, account.provider)
if (existing) return existing
await adapter.linkAccount(account)
Defensive patterns

Strategy: try-catch

Validate before calling

const existing = await adapter.getAccount(account.providerAccountId, account.provider)
if (existing) return existing
await adapter.linkAccount(account)

Try / catch

try {
  return await adapter.linkAccount(account)
} catch (e) {
  if (e.message === 'Account not created') {
    const existing = await adapter.getAccount(account.providerAccountId, account.provider)
    if (existing) return existing // idempotent retry
  }
  throw e
}

Prevention

When it happens

Trigger: surreal.create('account', ...) fails (connection, permissions, schema) or returns zero rows; duplicate account for the same provider/providerAccountId; invalid account fields from the provider profile.

Common situations: First OAuth sign-in where the account table has restrictive SurrealDB permissions; SurrealDB down or credentials wrong; account already linked causing an insert conflict that the empty catch hides.

Related errors


AI-assisted analysis of nextauthjs/next-auth@a1a16a5a77 (2026-08-28). Data as JSON: /api/errors/aa4fcfaddad1fe8e. Report an issue: GitHub.