Skip to content

fix: tolerate unknown SocketCategory values in SocketAlert.from_dict#79

Open
David Larsen (dc-larsen) wants to merge 2 commits intomainfrom
fix/socketcategory-lenient-parsing
Open

fix: tolerate unknown SocketCategory values in SocketAlert.from_dict#79
David Larsen (dc-larsen) wants to merge 2 commits intomainfrom
fix/socketcategory-lenient-parsing

Conversation

@dc-larsen
Copy link
Copy Markdown
Contributor

@dc-larsen David Larsen (dc-larsen) commented Apr 23, 2026

Summary

Fall back to SocketCategory.MISCELLANEOUS with a warning when SocketAlert.from_dict encounters an unknown category value instead of raising ValueError. Adds regression tests covering the known-value round trip, the unknown-value fallback, the warning log, and every currently defined category.

Fixes #78.

Problem

SocketAlert.from_dict calls SocketCategory(data["category"]) directly. If the API emits any value outside the current enum (supplyChainRisk | quality | maintenance | vulnerability | license | miscellaneous), the constructor raises ValueError and takes down the entire deserialization chain for the diff response:

StreamDiffResponse.from_dict
  -> FullScanDiffReport.from_dict
    -> DiffArtifacts.from_dict
      -> DiffArtifact.from_dict
        -> SocketAlert.from_dict
          -> SocketCategory(data["category"])   # ValueError here

Stack trace from the original report (issue #78):

ValueError: 'other' is not a valid SocketCategory
  File "socketdev/fullscans/__init__.py", line 450, in from_dict
    category=SocketCategory(data["category"]),
  File "socketdev/fullscans/__init__.py", line 517, in from_dict
    alerts=[SocketAlert.from_dict(alert) for alert in data.get("alerts", [])],
  File "socketdev/fullscans/__init__.py", line 556, in from_dict
    added=[DiffArtifact.from_dict(a) for a in data["added"]],
  File "socketdev/fullscans/__init__.py", line 616, in from_dict
    artifacts=DiffArtifacts.from_dict(data["artifacts"]),
  File "socketdev/fullscans/__init__.py", line 640, in from_dict
    data=FullScanDiffReport.from_dict(data_value) if data_value else None,
  File "socketdev/fullscans/__init__.py", line 873, in stream_diff
    return StreamDiffResponse.from_dict({"success": True, "status": 200, "data": result})

The reported trigger was the API returning "other" as an alert category. Because the error happens during response parsing, any consumer that calls stream_diff with use_types=True fails hard whenever a diff contains one of these alerts. socketsecurity hardcodes use_types=True at its single call site, so it has no toggle to work around this.

Fix

Catch ValueError, log a warning with the unrecognized value, and fall back to SocketCategory.MISCELLANEOUS:

try:
    category = SocketCategory(data["category"])
except ValueError:
    log.warning(
        "Unknown SocketCategory %r; falling back to MISCELLANEOUS. "
        "Upgrade socketdev to pick up newer categories.",
        data["category"],
    )
    category = SocketCategory.MISCELLANEOUS

MISCELLANEOUS is already the "doesn't fit the other buckets" member of the enum, so reusing it matches the semantic intent without adding a new value to the public contract. The warning surfaces the gap in logs without blocking deserialization.

Why this over the alternatives

  • Adding OTHER = "other" explicitly. Fixes the current symptom but leaves the SDK brittle to any future server-side category addition. The next new value would cause the same hard failure.
  • Adding a new UNKNOWN = "unknown" enum value. Explicit, but introduces a member the server never emits, and every downstream consumer would need to learn about it. MISCELLANEOUS is already in the contract.

Option 1 ("lenient deserialization") is the approach requested in the issue body.

Test plan

  • python -m pytest tests/unit/test_socket_alert_category.py -v (5 tests, 6 subtests pass):
    • known-value round trip
    • unknown-value fallback to MISCELLANEOUS
    • no ValueError raised for unknown values
    • warning log emitted naming the unrecognized category
    • every currently defined SocketCategory round trips through from_dict
  • python -m pytest tests/unit/ -v (99 passed, 1 pre-existing skip, no regressions)
  • Direct repro: SocketAlert.from_dict({"key": "k", "type": "t", "severity": "low", "category": "other"}) now returns an alert with category == SocketCategory.MISCELLANEOUS instead of raising.

Release note

socketdev.fullscans.SocketAlert.from_dict now accepts unknown category values, bucketing them as MISCELLANEOUS and emitting a warning log. Parsing behavior for known values is unchanged.

Version bumped to 3.0.33 to satisfy the check_version CI step.

The Socket API can emit category values the SDK does not yet know about
(e.g. "other"). Strict enum construction in SocketAlert.from_dict turned
that into a hard failure that propagated up through stream_diff and
crashed any consumer that happened to receive such an alert.

Fall back to SocketCategory.MISCELLANEOUS and log a warning when the
value is unrecognized, so the SDK stays forward-compatible with new
server-side categories without needing a coordinated release.

Fixes #78.
@dc-larsen David Larsen (dc-larsen) requested a review from a team as a code owner April 23, 2026 22:25
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 23, 2026

🚀 Preview package published!

Install with:

pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple socketdev==3.0.33.dev1

@lelia lelia self-assigned this Apr 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ValueError: 'other' is not a valid SocketCategory when parsing stream_diff response

2 participants