instructure/canvas-lms · info
[AUTH] Cookie data (present) failed to unmarshal…
Error message
[AUTH] Cookie data (present) failed to unmarshal. Inactivity timeout or invalid digest.
What it means
Canvas's enhanced cookie store decrypts/verifies and unmarshals session cookie data. If a cookie is present but unmarshals to nil — digest invalid, serialized payload corrupt, or session expired by inactivity — it logs this warning instead of raising, and the user gets a fresh empty session.
Solutions
- Benign for a single user — they just log in again; confirm new sessions work
- If widespread: ensure session secrets/signing keys are consistent across all app servers (no mixed old/new keys mid-rollout)
- Check for cookie truncation by proxies (keep session payload small)
- Verify no recent change to cookie store serializer/version and that inactivity timeout config matches expectations
Defensive patterns
Strategy: fallback
Validate before calling
# Caller-side: treat nil session as anonymous session_data = EnhancedCookieStore.unmarshal(cookie_data) user = session_data.present? ? load_user(session_data) : nil
Type guard
def valid_session?(data)
data.is_a?(Hash) && data.key?('session_id')
end Try / catch
# The store already swallows errors; callers should just check for nil session = store.unmarshal(data) if session.nil? # start a fresh anonymous session and require re-login end
Prevention
- Keep session secrets consistent across all app servers during deploys
- Keep cookies small to avoid proxy truncation
- Expect inactivity-timeout cookies to be common; never treat nil session as a server error
- Rotate secrets with overlap so old cookies still verify during rollout
When it happens
Trigger: A present, non-empty cookie's data fails Marshal.load or digest verification in unmarshal — inactivity-timeout expiry, stale cookie after a signing-secret change, or truncated/corrupted cookie data.
Common situations: Deploy that changed session store secrets or serialization; idle user past inactivity timeout reusing an old cookie; proxies truncating oversized cookies; cookie tampering; format changes across upgrades.
Understand the failure class
Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Attachment verifier token expired: #
- Attachment verifier token id mismatch. token id: #
- Authentication required to view other users' module progress
- can't build pseudonym_credentials except on just-generated…
- Cannot generate a services JWT without a 'sub' entry
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/d70c259349242ab2.
Report an issue: GitHub.
Appendix: source
Thrown at app/middleware/enhanced_cookie_store.rb:36
# with this program. If not, see <http://www.gnu.org/licenses/>.
class EnhancedCookieStore < ActionDispatch::Session::EncryptedCookieStore
def unmarshal(data, options = {})
unmarshalled_data = nil
begin
unmarshalled_data = super
rescue ArgumentError => e
# if the data being provided is not formatted in such a way that
# we can extract appropriately sized segments from it,
# then this is an auth problem (bad cookie), not a real
# exception. We'll return nil as though the cookie
# was unauthorized (and it is), and log the failure, but not explode because
# handling this as some 4xx is more accurate than a 500.
Canvas::Errors.capture_exception(:cookie_store, e, :info)
return nil
end
if unmarshalled_data.nil? && data.present?
Rails.logger.warn("[AUTH] Cookie data (present) failed to unmarshal. Inactivity timeout or invalid digest.")
end
unmarshalled_data
end
end
View on GitHub (pinned to 1c9f0bb801)