SG Ground Truth

loud and silent

A 400 is trustworthy and usually names the legal set, but a 200 proves nothing: an unknown field, sort key or query param is a no-op, and a batch can return an id for a row it never made.

API

Q Which failures does this API announce, and which does it swallow?

Endpoint POST /entity/<type>/_search ; POST /entity/<type>/_summarize ; GET /entity/<type> ; GET /schema/<Type> ; PUT /entity/<type>/{id}

Docs claim Silent. The REST docs describe success shapes and list no error vocabulary.

Actual

loud
  ["code", "definitely_not_an_operator", "x"]  400  API read() Version.code's 'text' data type doesn't
      support 'definitely_not_an_operator' 'relation'   source: ... Valid relations: ["contains",
      "not_contains", "is", "is_not", "starts_with", "ends_with", "in", "not_in"]
  _summarize {"field": "id", "type": "definitely_not_a_summary_type"}  400  Request Parameters invalid.
      source {"summary_fields": {"0": {"type": ["type must be one of: record_count, count, sum, maximum,
      minimum, average, earliest, latest, percentage, status_percentage, status_percentage_as_float,
      status_list, checked, unchecked"]}}}
  GET /entity/zzz_not_an_entity_type  404  detail "Entity type 'zzz_not_an_entity_type' does not exist."
  GET /schema/DisplayColumn           404  detail "Entity type 'DisplayColumn' does not exist."
  ["sg_not_a_field_at_all", "is", "x"] 400  API read() Version.sg_not_a_field_at_all doesn't exist.
  ["frame_count", "is", 2.5]           400  API read() Version.frame_count expected [String, Integer,
      NilClass] data type(s) but got Float: 2.5
  sort=''  400 {"sort": ["sort must be filled"]} ;  sort='id desc', '+id'  400 {"sort": ["sort list is not valid"]}

silent
  ?fields=code,zzz_not_a_field   200  attributes ['code']
  sort=code 200 sorted ; open_notes_count (summary), sg_uploaded_movie (url) and
      sg_not_a_field_at_all  200 each, ascending and descending, identical to no sort at all
  ["id", "in", [25529, 17055, 25553, 25493, 25541, 25481, 25517, 25505]]
      200  [17055, 25481, 25493, 25505, 25517, 25529, 25541, 25553]   id ascending
  sg_version_type, valid_values ['Type A', 'Type B', 'Type C'], over 100 rows:
      is 'Type A' 99 ; is 'zzz_not_a_valid_value' 0 ; in ['Type A'] 99 ;
      in ['Type A', 'zzz_not_a_valid_value'] 99 ; in ['zzz_not_a_valid_value'] 0
  PageSetting record_count  no filter 30145 ; settings_json contains 'ZZZNOPE' 30145 ; is null 30145 ;
      is_not null 30145 ; control [["page", "is", null]] 26372
  EventLogEntry record_count, one project 22811 ; + audit_trail is null, is_not null and
      contains {'x': 1}  22811 each ; control + event_type is 'ZZZNOPE'  0

Teaches

Every case below is measured elsewhere in the corpus; this entry is the map. The rows marked verified were re-run read-only on the date of this probe and none had changed.

Loud, and usually self-documenting. The rejection names the legal set, which is what made the field-type matrix cheap to build.

sent answer recorded
an operator no data type has 400 naming every legal relation for that data type. All 21 reachable types reject; 16 enumerate, the five unfilterable ones answer cannot be used in a filter (verified) probe 017, field_types/*
a _summarize type that is not one of the fourteen 400 Request Parameters invalid., source.summary_fields indexed by position, naming all fourteen (verified) probe 020
an entity type name that does not exist, in a path or in /schema 404 Entity type '<x>' does not exist., quoting the name back (verified) entity_types/Project, probe 023
a field name that does not exist, in a filter 400 API read() <Type>.<field> doesn't exist. (verified) probe 026
a list value outside valid_values, on a write 400 naming the legal values field_types/list
a wrong Python type, on a write or as a filter value 400 naming the accepted Ruby classes (verified as a filter value) field_types/number, float, percent
a malformed POST /entity/_batch body 400 per missing key, and request_type must be one of: create, update, delete probe 024
sort syntax: empty, a space, a leading + 400 sort must be filled or sort list is not valid (verified) probe 026

Silent. HTTP 200, and the part of the request the server did not understand is gone.

sent answer recorded
a name in ?fields that is not a field, on a read 200, the key absent from attributes (verified) probe 004, probe 023
?fields on a create or an update ignored entirely, both verbs, plain names and dotted paths alike probe 024
?fields=display_type,url on an Icon 200 with url reading "", which is indistinguishable from no image; adding image_data to the same request returns the real data URI, and omitting ?fields also returns it recipes/010
a list filter value outside valid_values 0 rows, no error; inside in the junk member is evaluated and matches nothing, so the rest of the list still returns (verified) field_types/list
sort on an unsortable or unknown field 200 in default order, identical to no sort, ascending and descending alike (verified) probe 026, field_types/summary, field_types/url
["id", "in", [...]] 200, id ascending; the order of the list is discarded (verified) probe 026
any filter on PageSetting.settings_json 200 and the full unfiltered set, while another field on the same type filters (verified) probe 023
any filter on EventLogEntry.audit_trail the same (verified) field_types/jsonb
["read_by_current_user", "in", [...]] on a Note 200 and the caller's unread rows, whatever the list holds; not_in and an is value outside read/unread answer the same. is "read" and is_not do filter probe 068
GET /schema/<Type>/fields/<field> for a field the census omits 200 with data: null, while a name that is nothing at all 404s Field '<Type>.<name>' does not exist. probe 068
filter[] query params on POST _search ignored entirely: a body filter wins and a bogus param name still returns 200, while the same param filters correctly on GET /entity/<type> probe 030
a batch create missing a required attribute 200 with an id for a row that does not exist: GET 404s, _search returns 0, DELETE answers 204. The single-create path 400s on the same body recipes/002_batch

Silent and destructive. Seven writes return success and either do nothing or destroy data. Not re-run here: they are recorded, and re-proving them costs rows.

written answer recorded
cached_display_name 200, the write discarded; the field re-reads as code field_types/text, entity_types/Sequence
Note.read_by_current_user as an ApiUser 200, the echo and the re-read both unread; the same write under sudo_as_login stores probe 068
Task.splits, any well-formed payload 200, null stored field_types/serializable
a multi_entity update mode spelled in the query string 200, the whole list replaced instead of appended field_types/multi_entity
an already-linked Shot added to a second Sequence.shots 200, the first Sequence's shots is now [] entity_types/Sequence
two summary_fields entries over one field 200, the second overwrites the first, last entry wins probe 020
PUT a Note with {"replies": []} 200, the Reply rows deleted outright entity_types/Note

The rule. Trust a 400: the request layer validates operator, summary type, entity name, field name and value class, and says what it wanted. Trust nothing about the parts of a request that select or shape data, because ?fields, sort, a filter value and an update mode are all dropped at 200 when the server does not recognise them, and a write is confirmed by re-reading the row, never by its status code.

Every entry on this site is the output of a probe in probes/. The corpus is generated by running those probes against a live Flow Production Tracking site, not written from memory.

Not affiliated with or endorsed by Autodesk. Flow Production Tracking is their product; this is an independent record of how its REST API answers.