Skip to content

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

Merged
lelia merged 2 commits intomainfrom
fix/socketcategory-lenient-parsing
Apr 24, 2026
Merged

fix: tolerate unknown SocketCategory values in SocketAlert.from_dict#79
lelia merged 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. Also fixes SocketDev/socket-python-cli#192.

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
@lelia lelia merged commit 065407a into main Apr 24, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants