HarperFast / HarperFast/harper

Operations API: ~25 malformed/wrong-type/out-of-range inputs return HTTP 500 instead of 4xx

Open
#1,416 1 comment 0 reactions 0 assignees View on GitHub
bug
Dominant language
JavaScript
Stars
89
Forks
10
Avg merge
2d 6h
Merged PRs (30d)
200

Description

## Summary

A systematic fuzz of the operations API (59 representative calls) found **25 that return HTTP 500** for inputs that are clearly client errors — malformed payloads, wrong-typed arguments, unknown operation variants, out-of-range values. The expected status for all is 4xx (400/422).

## Sample of 500-returning inputs

| Operation | Bad input | Expected | Actual |
|---|---|---|---|
| `set_configuration` | unknown key | 400 | 200 (silent drop) |
| `set_configuration` | `http.maxHeaderSize: -1` (accepted, bricks boot) | 400 | 200 / 500 on restart |
| `insert` | `records: "not-an-array"` | 400 | 500 |
| `insert` | `records: [42]` (non-object element) | 400 | 500 |
| `update` | `records: null` | 400 | 500 |
| `upsert` | missing `table` key | 400 | 500 |
| `upsert` | `table: 12345` (integer) | 400 | 500 |
| `search_by_conditions` | degenerate single-child `or` | 400 | 500 |
| `search_by_conditions` | `limit: "ten"` | 400 | 500 |
| `search_by_value` | `limit: -5` | 400 | 500 |
| `bulk_load` | `path` points to a non-existent file | 400 | 500 |
| `drop_table` | non-existent table | 400 | 500 |
| `csv_data_load` | `csv_file_path` missing | 400 | 500 |

(25 of 59 tested; the table above is a representative sample — full list in the qa-scratch test output.)

## Pattern

The common thread is that Joi validation (the first layer) catches type and enum errors but has incomplete coverage for range constraints (numeric min/max), missing-but-required sub-keys, and wrong-shape values inside arrays. When Joi passes an input that the engine then rejects, the engine throws an unguarded `Error` that bubbles to 500.

This is the same "client errors as HTTP 500" pattern noted on #1299 (GraphQL auth), #1397 (SQL unsupported constructs), and F-030 (REST `?select`).

## Recommendation

- Add a Joi (or equivalent) validation pass that returns 4xx before the operation reaches the engine for the missing-required / wrong-type / out-of-range cases listed above.
- Alternatively, an error-class convention where the engine throws a typed `ClientError` subclass that the transport layer maps to 400.
- Long-term: a single "client error → 4xx" middleware pass would close all instances of this pattern across REST, GraphQL, SQL, and ops-API.

**Harper:** `7aaa5a152`; byte-identical to `main` @`6797f091d`.
**Repro test:** `integrationTests/qa-scratch/qa147-ops-fuzz.test.ts`

---
*Surfaced by the QA-explorer exploratory campaign for @kris (QA-147). Filed by Claude (Sonnet 4.6) for @kris.*

Contributor guide

Open the contributing guide

Research direction

Start by running integrationTests/qa-scratch/qa147-ops-fuzz.test.ts and reviewing the Operations API validation and error-handling entry points it exercises. Compare the listed malformed, wrong-type, missing-key, and out-of-range cases with the current Joi checks and transport responses. Done means the identified client-error inputs return 4xx responses instead of 500, without changing valid operation behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, node.js, typescript
Domain
api, backend, testing-qa
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.