gofiber/fiber · warning

csrf: unexpected value type %T in storage

Error message

csrf: unexpected value type %T in storage

What it means

Thrown at middleware/csrf/storage_manager.go:48 on the in-memory fallback path: memory.Get(key) returned a non-nil value whose Go type is not []byte. The CSRF storage manager expects byte slices in its private memory.Storage; any other type means the store was contaminated by another writer under a colliding key.

Source

Thrown at middleware/csrf/storage_manager.go:48

		storageManager.memory = memory.New()
	}
	return storageManager
}

// get raw data from storage or memory
func (m *storageManager) getRaw(ctx context.Context, key string) ([]byte, error) {
	if m.storage != nil {
		raw, err := m.storage.GetWithContext(ctx, key)
		if err != nil {
			return nil, fmt.Errorf("csrf: failed to get value from storage: %w", err)
		}
		return raw, nil
	}

	if value := m.memory.Get(key); value != nil {
		raw, ok := value.([]byte)
		if !ok {
			return nil, fmt.Errorf("csrf: unexpected value type %T in storage", value)
		}
		return raw, nil
	}

	return nil, nil
}

// set data to storage or memory
func (m *storageManager) setRaw(ctx context.Context, key string, raw []byte, exp time.Duration) error {
	if m.storage != nil {
		if err := m.storage.SetWithContext(ctx, key, raw, exp); err != nil {
			return fmt.Errorf("csrf: failed to store key %q: %w", m.logKey(key), err)
		}
		return nil
	}

	m.memory.Set(key, raw, exp)
	return nil

View on GitHub (pinned to 9a4c7e57fe)

Solutions

  1. Stop sharing one *memory.Storage across middlewares that store different types; let CSRF allocate its own (default when Storage is nil).
  2. Namespace keys with distinct prefixes if sharing a store is unavoidable.
  3. Reset memory.Storage between tests to avoid cross-test contamination.
  4. Audit every .Set call on the shared store to ensure only []byte values land on CSRF keys.

Example fix

// before (bug): shared store across CSRF and another component
shared := memory.New()
app.Use(csrf.New(csrf.Config{ /* injects shared via custom wiring */ }))

// after: each middleware owns its private store
app.Use(csrf.New()) // Storage nil -> private memory.Storage, no type collision
Defensive patterns

Strategy: type-guard

Validate before calling

// Ensure CSRF owns its memory store; don't inject a shared one.
if cfg.Storage == nil && cfg.Session == nil {
    // newStorageManager(nil, ...) allocates a private *memory.Storage - safe.
}

Type guard

func asCSRFBytes(v any) ([]byte, bool) {
    b, ok := v.([]byte)
    return b, ok
}

Try / catch

if v := m.memory.Get(key); v != nil {
    raw, ok := v.([]byte)
    if !ok {
        // programming error - log loudly, treat as no token
        log.Printf("unexpected csrf value type %T", v)
        return nil, nil
    }
    return raw, nil
}

Prevention

When it happens

Trigger: Only fires when CSRF is configured without an explicit Storage (so it allocates its own memory.Storage) AND that same store pointer is shared with another component writing non-[]byte values under colliding keys. The default newStorageManager allocates a private store, so this should never occur in normal wiring.

Common situations: Test harness sharing one memory.Storage across cache + CSRF middlewares; custom fork that injects a shared store; deliberate key-prefix reuse across components during development.

Related errors


AI-assisted analysis of gofiber/fiber@9a4c7e57fe (2026-08-04). Data as JSON: /data/errors/cb4261690dc15b37.json. Report an issue: GitHub.