nextauthjs/next-auth · error
Couldn't create session
Error message
Couldn't create session
What it means
createSession inserts a session row and immediately re-selects it by session token in the same batch; if the SELECT yields nothing the adapter throws this error. The insert did not produce a readable session, so no session can be returned to the auth core.
Source
Thrown at packages/adapter-d1/src/index.ts:274
await deleteRecord(
db,
DELETE_ACCOUNT_BY_PROVIDER_AND_PROVIDER_ACCOUNT_ID_SQL,
[provider, providerAccountId]
)
},
async createSession({ sessionToken, userId, expires }) {
const id = crypto.randomUUID()
const createBindings = [id, sessionToken, userId, expires.toISOString()]
const getBindings = [sessionToken]
const session = await createRecord<AdapterSession>(
db,
CREATE_SESSION_SQL,
createBindings,
GET_SESSION_BY_TOKEN_SQL,
getBindings
)
if (session) return session
throw new Error(`Couldn't create session`)
},
async getSessionAndUser(sessionToken) {
const session: any = await getRecord<AdapterSession>(
db,
GET_SESSION_BY_TOKEN_SQL,
[sessionToken]
)
if (session === null) return null
const user = await getRecord<AdapterUser>(db, GET_USER_BY_ID_SQL, [
session.userId,
])
if (user === null) return null
return { session, user }
},
async updateSession({ sessionToken, expires }) {
if (expires === undefined) {View on GitHub (pinned to a1a16a5a77)
Solutions
- Run the adapter's migration SQL so sessions (and accounts/users) tables exist with the expected columns.
- Verify the userId passed exists in the users table before creating a session.
- Check the D1 binding points at the same database used for users.
- Update the adapter if you rely on batch insert+select on local D1/miniflare.
Example fix
// before
await adapter.createSession({ sessionToken, userId: unknownId, expires })
// after
const user = await adapter.getUser(unknownId)
if (!user) throw new Error('cannot create session for missing user')
await adapter.createSession({ sessionToken, userId: unknownId, expires }) Defensive patterns
Strategy: validation
Validate before calling
const user = await adapter.getUser(sessionData.userId)
if (!user) throw new Error('cannot create session: userId does not exist') Type guard
function isCreateSessionInput(s: unknown): s is AdapterSession {
return !!s && typeof s === 'object' && typeof (s as AdapterSession).sessionToken === 'string' && (s as AdapterSession).expires instanceof Date
} Try / catch
try {
const session = await adapter.createSession({ sessionToken, userId, expires })
} catch (e) {
if (e instanceof Error && e.message === "Couldn't create session") {
// check sessions table exists and userId is valid, then retry or re-authenticate
}
throw e
} Prevention
- Run migrations so the sessions table exists
- Validate userId refers to an existing user before creating sessions
- Use consistent expires values (Date objects) as the adapter expects
- Test session flows on the same D1 environment you deploy to
When it happens
Trigger: adapter.createSession({ sessionToken, userId, expires }) when the INSERT fails or the follow-up GET_SESSION_BY_TOKEN_SQL returns no row — sessions table missing, userId referencing a non-existent user, or schema mismatch.
Common situations: Sessions table never migrated, foreign-key mismatch on userId, custom session table names, expired/invalid expires value rejected by constraints, or local miniflare D1 batch quirks.
Related errors
- Error creating user: Cannot get user after creation.
- Error updating user: Cannot get user after updating.
- Error updating user: Failed to run the update SQL.
- [createSession] Failed to fetch created session
- userId is undef in createSession
AI-assisted analysis of nextauthjs/next-auth@a1a16a5a77 (2026-08-28).
Data as JSON: /api/errors/ffc56843303a64d0.
Report an issue: GitHub.