Skip to content

API: input validation missing on common mutations (empty/invalid inputs accepted silently) #111

@MajorTal

Description

@MajorTal

Summary

Several mutation operations accept inputs that violate basic invariants and persist them. This is on top of #108 (validate phase doesn't validate) — these cases reproduce even on phase: "execute".

All reproduce against production eagles.kychon.com.

Cases

1. forum.topics.create accepts entirely empty input

As active_member with input: {}:

{
  "result": {
    "id": 10128,
    "category_id": null,
    "title": "Untitled",
    "body": "",
    ...
  }
}

Creates an "Untitled" topic with no category, no body. Members can spam orphan topics with no required fields.

Expected: validation.failed requiring at least category_id + title.

2. events.create accepts backwards dates (ends_at < starts_at)

As admin:

-d '{"...input":{"title":"foo","starts_at":"2099-12-31T23:59:59Z","ends_at":"2026-01-01T00:00:00Z"}}'

Event is created with ends_at ~74 years before starts_at.

Expected: validation.failed on the date ordering.

3. events.create accepts negative capacity

-d '{"...input":{"title":"foo","capacity":-100,"starts_at":"2099-...","ends_at":"2099-..."}}'

Capacity -100 persists as-is.

Expected: validation.failed or coerce to 0.

4. rsvps.setStatus accepts arbitrary status string

As active_member:

-d '{"...input":{"event_id":6754,"status":"hacking_attempt"}}'

Returns ok: true with status: "hacking_attempt" stored. No enum check.

Expected: validation.failed requiring status in (going, not_going, maybe, cancelled — whatever the agreed enum is).

5. events.create / tiers.create with garbage types return opaque internal.error

-d '{"...operation":"events.create","input":{"title":"x","starts_at":"not-a-date","ends_at":"banana"}}'
# → {"ok":false,"error":{"code":"internal.error","message":"Execution failed for events.create.","retryable":true}}

Bad type should return validation.failed with the offending field; instead it returns internal.error with retryable: true (which is wrong — same input will fail the same way).

Why this matters

  • Forum data quality (orphan "Untitled" topics).
  • Calendar correctness (negative-duration events break list/render code).
  • Capacity logic (negative numbers break "available seats" math).
  • Audit/analytics on RSVP states is meaningless if the status column is free-form text.
  • retryable: true on validation-class errors causes well-behaved clients to retry indefinitely.

Suggested approach

Add a per-operation input schema (Zod or similar) wired through executeMutation and createActionPlan (so validate enforces the same — see #108). Map schema failures to validation.failed with structured detail.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions