operations.receive3: versions published by a 2026.9 connector need that build, and their full data shape only comes through operations.receive3. Speckle does not guarantee that older specklepy builds, or operations.receive, keep working against current servers. This page shows each change side by side so you can judge how much of your script moves.
The old path is PAT → operations.receive → walk a Base tree. The 2026.9 path is PAT → operations.receive3, which returns a Model with columnar properties and typed relations. For the data model itself, see Object model. For dates and who must act, see Data model migration for developers.
What changes for a script
Update specklepy first
Install a 2026.9 specklepy with thebundle extra. 2026.9.0b3 is the first public build that loads 2026.9 versions. A later stable 2026.9.0 replaces the beta pin; the calls on this page do not change.
version.referenced_object is a bundle reference such as bundle.<projectId>.<modelId>.<versionId>, not a content hash. An older specklepy treats that string as an object id, requests it from the objects API, and receives a 404 whose body tells you to upgrade.
Load a model
operations.receive3 takes an Account plus project, model, and version ids, and returns a Model. Use it as a context manager: it owns the downloaded bundle files on disk until the with block ends.
Auth and version lookup stay as on Authentication and the Quickstart. The snippets below assume account, client, transport, project_id, model_id, and version_id are already in scope. Build account with Account.from_token and a PAT, use client.account after you authenticate, or call get_default_account().
- Prior to 2026.9 (receive)
- 2026.9 (receive3)
Prior to 2026.9
operations.receive3 works for every version that has a bundle, including older versions
converted by the server. If an older stored version has not been converted, or its conversion
could not complete, receive3 raises a SpeckleException. Use operations.receive only while
that version’s object graph remains available. On current servers, sends from older connectors are
bundled before the new version becomes visible.Count and filter objects
Before 2026.9 you walk aBase tree. In 2026.9, objects are a flat list. Properties are path-keyed ("category", "Constraints.Base Offset"). Relations are accessors, not proxy lists.
- Prior to 2026.9
- 2026.9
Prior to 2026.9
model.object_by_application_id(id). application_id is the only identity a bundle object has. Do not treat Base.id as a content hash on a 2026.9 version.
Replace property walks
Before 2026.9, nested parameters are dictionaries you walk:obj.properties["x"] then ["y"]. In 2026.9 those paths are flat, and PropertyView replaces the walk. ModelObject.properties is already this view.
get_string/get_double/get_bool: typed lookup.Noneif the path is missing or the value is another type. Instance properties first, then type properties, then root scalars.- Indexer (
obj["path"]): untyped lookup, same order. properties.under("Constraints"): the subtree under that prefix, with the prefix stripped.to_nested(): the old nested-dictionary tree. Allocates. Use it only when a caller still needs that shape.
get_string / get_double for a single path. Use under when you need a group.
The snippets below assume wall is already in scope: a DataObject from the tree, or a ModelObject from model.objects.
- Prior to 2026.9
- 2026.9
Prior to 2026.9
Replace proxy walks
Before 2026.9, grouping by level or material meant indexingapplicationIds and resolving proxy
objects lists. In 2026.9, use the typed relation accessors directly. See
Relations for the names.
2026.9
elements tree and no proxy objects lists. Do not unpack proxies to rebuild containment; read the relation accessors instead.
Read versions published before 2026.9
Useoperations.receive3 for every version that has a bundle. Keep operations.receive only as a
fallback for an older stored version that has no bundle and whose object graph remains available.
- Versions published before 2026.9: pass
referenced_objectas a content hash and get the object graph back. - Versions published by a 2026.9 connector:
referenced_objectis a bundle reference (bundle.<projectId>.<modelId>.<versionId>). A 2026.9 specklepy recognizes the prefix and returns a best-effortBasetree (Model.to_base(), DataObject idiom,version = 4on the root). That projection does not scale to the model sizes the bundle format is built for, and it is not a lossless round trip. It needs an authenticatedServerTransportfor the reference’s project. Do not build new work on it. - Older specklepy: fetching a bundle reference from the objects API returns 404 with upgrade guidance. Upgrade specklepy rather than parsing the 404 body.
Publish from a script
Most analysis scripts only receive. If your script callsoperations.send then client.version.create, move it to operations.send3 with a BundleBuilder. Publishing an object graph is deprecated, and Speckle does not guarantee it for new work; see Publish through model ingestions.
send3 returns a SendResult with a reserved version_id as soon as the upload finishes. The version appears in queries and at its URL, and fires webhooks, when the server finishes processing. Poll client.version.get if the same script needs the version to exist.
2026.9
FAQ
Can I keep my operations.receive script as it is?
Can I keep my operations.receive script as it is?
No, not any longer. Install
specklepy[bundle]==2026.9.0b3 and load versions with
operations.receive3. Older specklepy builds get a 404 on versions from a 2026.9 connector, and
Speckle does not guarantee they keep working against current servers. Keep operations.receive
only to read versions published before 2026.9 that have no bundle.Why does receive3 return Model instead of Base?
Why does receive3 return Model instead of Base?
Model is the bundle itself: objects, path-keyed properties, and relation accessors, with
geometry parsed only when you ask. A Base tree inflates every object and mesh into Python
objects, which is why operations.receive does not suit the new format.What happens if I forget to close Model?
What happens if I forget to close Model?
The downloaded parquet files stay in a scratch directory until
close runs. Always use a with
block. Objects and geometry you already read stay in memory after close; geometry you have not
touched cannot be read afterwards.Can I keep using ServerTransport?
Can I keep using ServerTransport?
Only to read versions published before 2026.9. Load everything else with
operations.receive3,
which takes an account instead of a transport.Why did parameter['value'] stop working?
Why did parameter['value'] stop working?
On a 2026.9 version, parameter metadata is collapsed to scalars on dotted paths. Read the value
with
get_double or obj["Width"], not from a metadata wrapper. That is an intended change,
not a bug in your filter.