nextauthjs/next-auth · error

Object is nullish

Error message

Object is nullish

What it means

The Hasura adapter's format.from mapper converts Hasura rows into Auth.js user/session objects. Callers like createUser/getUser pass throwIfNullish when a null result is unacceptable, and format.from then throws 'Object is nullish' instead of returning null. It fires whenever the input object is undefined, null, or otherwise falsy and the caller demanded a non-null result.

Source

Thrown at packages/adapter-hasura/src/index.ts:183

        DeleteVerificationTokenDocument,
        params
      )
      const verificationToken = delete_verification_tokens?.returning?.[0]

      return format.from(
        useFragment(VerificationTokenFragmentDoc, verificationToken)
      )
    },
  }
}

export const format = {
  from<T, B extends boolean = false>(
    object?: Record<string, any> | null | undefined,
    throwIfNullish?: B
  ): B extends true ? T : T | null {
    if (!object) {
      if (throwIfNullish) throw new Error("Object is nullish")
      return null as any
    }

    const newObject: Record<string, unknown> = {}

    for (const [key, value] of Object.entries(object))
      newObject[key] = isDate(value) ? new Date(value) : value

    return newObject as T
  },
  to<T>(object: Record<string, any>): T {
    const newObject: Record<string, unknown> = {}

    for (const [key, value] of Object.entries(object))
      newObject[key] = value instanceof Date ? value.toISOString() : value

    return newObject as T
  },

View on GitHub (pinned to a1a16a5a77)

Solutions

  1. Confirm the record exists in Hasura before calling the adapter, or handle the throw in try/catch
  2. Verify the adapter's table and field mappings match the actual Hasura schema
  3. Check the Hasura endpoint/role permissions allow the query to see the row (row-level permissions can filter it out)
  4. Clear stale auth cookies referencing deleted users

Example fix

// before
const user = await adapter.getUserByEmail(email) // throws if missing
// after
let user = null
try {
  user = await adapter.getUserByEmail(email)
} catch {
  user = null
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (!email) throw new Error('email required before getUserByEmail')

Type guard

function isRow(v: unknown): v is Record<string, unknown> {
  return v !== null && typeof v === 'object'
}

Try / catch

try {
  user = await adapter.getUserByEmail(email)
} catch (e) {
  if ((e as Error).message === 'Object is nullish') user = null
  else throw e
}

Prevention

When it happens

Trigger: Calling getUser/getUserByEmail/getUserByAccount with an id/email/provider-account that has no matching Hasura row, deleteUser/updateUser on a nonexistent record, or Hasura returning no rows due to wrong table/field mapping in the adapter config.

Common situations: Typo'd email lookup, stale cookie referencing a deleted user, Hasura GraphQL query returning errors mapped to undefined, adapter table/column mapping misconfigured so queries always return empty.

Related errors


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