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
- Check SurrealDB connectivity and that the `account` table exists and is writable by the adapter user
- Inspect SurrealDB permissions/DEFINE TABLE PERMISSIONS so the adapter role can CREATE on account
- Look for an existing account row with the same provider + providerAccountId (duplicate link attempt)
- 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
- Make linkAccount calls idempotent by checking getAccount first
- Grant CREATE permission on the account table for the adapter DB user
- Monitor SurrealDB connection errors; the adapter swallows root causes
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
- User id is required
- User not updated
- Verification Token not created
- Verification Token not used
- Authenticator not created
AI-assisted analysis of nextauthjs/next-auth@a1a16a5a77 (2026-08-28).
Data as JSON: /api/errors/aa4fcfaddad1fe8e.
Report an issue: GitHub.