Skip to content

bug: Model.from_storage raises KeyError for missing optional fields #418

@nycomp

Description

@nycomp

Bug Description

The Model.from_storage() class method in campus/model/base.py raises a KeyError when loading storage records that are missing optional fields (fields with default values), even though those fields are correctly defined with defaults in the model.

Root Cause

In campus/model/base.py:110, the from_storage method uses direct dictionary access:

field.name: record[field.name]  # Raises KeyError if key missing

This fails when the storage record doesn't contain a field that has a default value in the model definition.

Impact

This bug affects OAuth token loading when campus tokens (which don't have refresh_token) are stored and then retrieved from MongoDB. The OAuthToken model correctly defines:

refresh_token: str | None = None

But when from_storage() is called on a campus token record (which never stores refresh_token), it raises KeyError: 'refresh_token'.

Example Affected Flow

  1. User signs in via campus-profile OAuth flow
  2. Campus auth creates a token without refresh_token (campus tokens don't have refresh tokens)
  3. Token is stored in MongoDB without the refresh_token field
  4. On subsequent sign-in, loading the token from storage fails with KeyError: 'refresh_token'

Proposed Fix

The from_storage method should:

  1. Use record.get(field.name) for optional fields with defaults
  2. Fall back to the field's default value when the key is missing
  3. Only raise KeyError for truly required fields (those without defaults)

Files Affected

  • campus/model/base.py - Model.from_storage() method

Related

  • OAuth flow uses this in campus/model/credentials.py for OAuthToken model
  • MongoDB backend stores documents sparsely (missing keys for null/undefined values)

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions