Skip to content

benchy-mesh: the mesh validation engine

The engine that reads a 3D file inside fixed limits and returns one report of what it checked and found.

What it checks

benchy-mesh is the engine behind every file check Benchy runs. It identifies a 3D file from its contents rather than its name, parses STL, OBJ, GLB/glTF and 3MF inside fixed limits, measures geometry and topology, and produces one report: the checks that ran, how fully each covered the file, the issues raised, and a print-readiness assessment built only from checks the file passed.

The same engine and report are used wherever Benchy checks a file. What the report says depends on the policy, the context of the check, and the resource limits it was given.

Parser limits

Uploaded bytes are untrusted: an extension or declared media type is only a hint, and parsing runs inside explicit limits on bytes, counts, allocations, strings, textures, archive entries and expansion. That catches:

  • Truncation and lying headers — a binary STL whose triangle count doesn't match its body, a GLB whose chunk lengths overrun the file, a header with no body.
  • Poisoned geometry — NaN and infinite vertices in STL and OBJ are reported without contaminating the bounds or other measurements.
  • Archive attacks in 3MF — compression-ratio and expansion limits stop zip bombs, invalid internal paths are rejected, entry counts are capped, and the model part must be the one the archive's relationships point at.
  • Resource exhaustion — every unit of work is bounded by the execution profile in force.

Each failure carries a stable issue code, such as BINARY_STL_LENGTH_MISMATCH, INVALID_ARCHIVE_PATH or ARCHIVE_COMPRESSION_RATIO_LIMIT_EXCEEDED.

The JSON contract

A result (MeshValidationResult, abridged below) is camelCase, at schemaVersion: 2. The schema version fixes what the fields mean; the policy version changes whenever a check, threshold, issue, coverage rule, parser decision or verdict could differ for the same bytes. Branch on codes and enums, never on the English summaries.

json
{
  "schemaVersion": 2,
  "policyVersion": "2026.10.03.1",
  "validationProfile": "marketplace_publish",
  "executionMode": "server_enforced",
  "identification": {
    "detectedFormat": "stl",
    "confidence": "high",
    "evidence": ["content_format_signal", "bounded_parser_completed"]
  },
  "decision": { "verdict": "allow", "reasonCodes": [] },
  "checks": [
    { "id": "format.structure", "status": "passed", "coverage": "full", "summary": "…" }
  ],
  "issues": [],
  "printReadiness": {
    "assessment": "ready",
    "checks": [ … ],
    "notes": [],
    "limitations": []
  },
  "ok": true,
  "format": "stl",
  "sha256": "…"
}

The policy version above is an example; read the one in each report.