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

  1. Retry the device authorization request (with backoff) — fosite clients are expected to treat ErrSerializationFailure as retryable.
  2. Enable the SQL retry wrapper (e.g. max_concurrent_retries / retry configuration for the store) so the driver retries transparently.
  3. Check for client-side duplicate requests causing races and add idempotency on the caller.
  4. 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

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


AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03). Data as JSON: /api/errors/2f5ff1ac218fd002. Report an issue: GitHub.