ory/hydra · error · fosite.RFC6749Error
server_error
server_error
Error message
serialization failure
What it means
CreateDeviceAuthSession wraps fosite.ErrSerializationFailure (with hint message "serialization failure") when the underlying INSERT fails with a SQL concurrent-update error (sqlcon.ErrConcurrentUpdate). Fosite uses this sentinel to signal a transaction serialization conflict so the OAuth2 layer can retry the request. It surfaces with code server_error in the OAuth2 error response.
Source
Thrown at persistence/sql/persister_device.go:166
Session: session,
Subject: subject,
DeviceCodeActive: true,
UserCodeState: r.GetUserCodeState(),
}, nil
}
// CreateDeviceCodeSession creates a new device code session and stores it in the database. Implements DeviceAuthStorage.
func (p *Persister) CreateDeviceAuthSession(ctx context.Context, deviceCodeSignature, userCodeSignature string, requester fosite.DeviceRequester) (err error) {
ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateDeviceCodeSession")
defer otelx.End(span, &err)
req, err := p.sqlDeviceSchemaFromRequest(ctx, deviceCodeSignature, userCodeSignature, requester, requester.GetSession().GetExpiresAt(fosite.DeviceCode).UTC())
if err != nil {
return err
}
if err := sqlcon.HandleError(p.CreateWithNetwork(ctx, req)); errors.Is(err, sqlcon.ErrConcurrentUpdate()) {
return errors.Wrap(fosite.ErrSerializationFailure, err.Error())
} else if errors.Is(err, sqlcon.ErrUniqueViolation()) {
return errors.Wrap(fosite.ErrExistingUserCodeSignature, err.Error())
} else if err != nil {
return err
}
return nil
}
// GetDeviceCodeSession returns a device code session from the database. Implements DeviceAuthStorage.
func (p *Persister) GetDeviceCodeSession(ctx context.Context, signature string, session fosite.Session) (_ fosite.DeviceRequester, err error) {
ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetDeviceCodeSession")
defer otelx.End(span, &err)
r := DeviceRequestSQL{}
if err = p.QueryWithNetwork(ctx).Where("device_code_signature = ?", signature).First(&r); errors.Is(err, sql.ErrNoRows) {
return nil, errors.WithStack(fosite.ErrNotFound)
} else if err != nil {View on GitHub (pinned to 4174065ffb)
Solutions
- Retry the device authorization request (with backoff) — fosite clients are expected to treat ErrSerializationFailure as retryable.
- Enable the SQL retry wrapper (e.g. max_concurrent_retries / retry configuration for the store) so the driver retries transparently.
- Check for client-side duplicate requests causing races and add idempotency on the caller.
- Consider a database with proper row-level locking or reduce isolation level contention (e.g. MySQL deadlock settings).
Defensive patterns
Strategy: retry
Try / catch
if fosite.ErrSerializationFailure.Is(err) /* or errors.Is hint check */ {
// transient conflict: retry CreateDeviceAuthSession with exponential backoff
} Prevention
- Retry device authorization on serialization failure hints before surfacing errors to users.
- Configure SQL max_concurrent_retries in the deployment.
- Avoid duplicate/parallel device authorization submissions from clients.
When it happens
Trigger: Two concurrent device authorization attempts (or a unique/constraint race under a transaction isolation level that reports concurrent update, e.g. MySQL InnoDB) causing the INSERT into the device auth table to conflict; high-concurrency device login polls hitting the same rows.
Common situations: Multiple replicas of Hydra receiving device authorization requests simultaneously; MySQL deployments with REPEATABLE READ hitting lock conflicts; client retry storms on the device authorization endpoint.
Related errors
- server_error
- invalid_request
- issuer URL must be set unless development mode is enabled
- issuer URL scheme must be HTTPS unless development mode is e
- The DSN connection string looks like a SQLite connection, bu
AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03).
Data as JSON: /api/errors/2f5ff1ac218fd002.
Report an issue: GitHub.