# Update properties safely

Location: [gRPC API](https://developer.m-files.com/APIs/gRPC-API/index.md) > [Guides](https://developer.m-files.com/APIs/gRPC-API/index.md#guides)

HTML version: https://developer.m-files.com/APIs/gRPC-API/guides/update-properties/

Every change to an object's properties creates a new version. Base the change on the version you
read, so that the server refuses it if someone else changed the object in between. There are two
ways:

* **A. One call.** [SetProperties](https://developer.m-files.com/APIs/gRPC-API/Reference/MFiles.IRPCObjectOperations/SetProperties/index.md) on a
  checked-in object: the server checks the object out, sets the properties and checks it in.
* **B. Check out, change, check in.** [CheckOut](https://developer.m-files.com/APIs/gRPC-API/Reference/MFiles.IRPCObjectOperations/CheckOut/index.md),
  any number of `SetProperties` calls on the checked-out version, then
  [CheckIn](https://developer.m-files.com/APIs/gRPC-API/Reference/MFiles.IRPCObjectOperations/CheckIn/index.md). All changes become one new version.

## Calls

`SetProperties` fields:

| Field | A. checked-in object | B. checked-out object |
|---|---|---|
| `obj_ver` | The object and the version you read | The object and the checked-out version from `CheckOut` |
| `allow_modifying_checked_in_object` | true | unset |
| `fail_if_newer_version_exists` | true: refuse if a newer version exists | unset |
| `properties` | The values to add or replace | The values to add or replace |
| `remove_unspecified_properties` | false: keep all other properties | false |

* `CheckOut` takes the `obj_id`; the checked-out version is
  `object_info.object_version.version_info.version` of its response.
* `CheckIn` takes the `obj_ver` of the checked-out version.
* The response of `SetProperties` and `CheckIn` has the new latest version in
  `object_info.latest_version` (version information and properties).

## Code

The recipe creates a test document, sets Keywords (1004) in one call (A), then checks the
document out, sets Keywords and Document date (1002) in one `SetProperties` call, and checks it
in (B). If anything fails while the document is checked out, it undoes the check-out. At the end
it deletes the document, unless you pass `--keep`.

### Python

```python
# One call: the server checks the object out, sets the values and checks it in.
# Name the version you read; with fail_if_newer_version_exists the call fails instead
# of overwriting a change someone else made after that version.
updated = objects.SetProperties(ops.SetPropertiesRequest(
    obj_ver=obj_ver(object_id.type, object_id.item_id.internal_id, version),
    allow_modifying_checked_in_object=True,
    fail_if_newer_version_exists=True,
    # Other properties stay as they are (remove_unspecified_properties is false).
    properties=[property_value(1004, text("grpc, sample"))]))  # Keywords
version = updated.object_info.latest_version.object_version.version_info \
    .version.internal_version
print(f"Set Keywords: now version {version}")
```

*Source: [python/recipes/update_properties.py](https://developer.m-files.com/APIs/gRPC-API/downloads/samples/python/recipes/update_properties.py)*

```python
def check_out_set_check_in(objects, object_id) -> None:
    """Check out, set, check in: several changes become one new version, and nobody else can
    change the object meanwhile."""
    checked_out = objects.CheckOut(ops.CheckOutRequest(obj_id=object_id))
    working_version = checked_out.object_info.object_version.version_info.version
    print(f"Checked out: working version {working_version.internal_version}")
    working = obj_ver(object_id.type, object_id.item_id.internal_id,
                      working_version.internal_version)
    try:
        objects.SetProperties(ops.SetPropertiesRequest(
            obj_ver=working,
            properties=[
                property_value(1004, text("grpc, sample, checked out")),       # Keywords
                property_value(1002, date(datetime.now(timezone.utc).date())),  # Document date
            ]))
        checked_in = objects.CheckIn(ops.CheckInRequest(obj_ver=working))
    except Exception:
        # Do not leave the object checked out.
        objects.UndoCheckout(ops.UndoCheckoutRequest(obj_ver=working))
        raise
    version = checked_in.object_info.latest_version.object_version.version_info.version
    print(f"Checked in: now version {version.internal_version}")
```

*Source: [python/recipes/update_properties.py](https://developer.m-files.com/APIs/gRPC-API/downloads/samples/python/recipes/update_properties.py)*

### C#

```csharp
// One call: the server checks the object out, sets the values and checks it in.
// Name the version you read; with fail_if_newer_version_exists the call fails instead
// of overwriting a change someone else made after that version.
var updated = await objects.SetPropertiesAsync(new SetPropertiesRequest
{
    ObjVer = ObjVer(objId.Type, objId.ItemId.InternalId, version),
    AllowModifyingCheckedInObject = true,
    FailIfNewerVersionExists = true,
    // Other properties stay as they are (remove_unspecified_properties is false).
    Properties = { Property(1004, Text("grpc, sample")) },  // Keywords
});
version = updated.ObjectInfo.LatestVersion.ObjectVersion.VersionInfo.Version.InternalVersion;
Console.WriteLine($"Set Keywords: now version {version}");
```

*Source: [csharp/Recipes/UpdateProperties.cs](https://developer.m-files.com/APIs/gRPC-API/downloads/samples/csharp/Recipes/UpdateProperties.cs)*

```csharp
// Check out, set, check in: several changes become one new version, and nobody else
// can change the object meanwhile.
var checkedOut = await objects.CheckOutAsync(new CheckOutRequest { ObjId = objId });
var workingVersion = checkedOut.ObjectInfo.ObjectVersion.VersionInfo.Version;
Console.WriteLine($"Checked out: working version {workingVersion.InternalVersion}");
try
{
    var working = ObjVer(objId.Type, objId.ItemId.InternalId, workingVersion.InternalVersion);
    await objects.SetPropertiesAsync(new SetPropertiesRequest
    {
        ObjVer = working,
        Properties =
        {
            Property(1004, Text("grpc, sample, checked out")),             // Keywords
            Property(1002, Date(DateOnly.FromDateTime(DateTime.UtcNow))),  // Document date
        },
    });
    var checkedIn = await objects.CheckInAsync(new CheckInRequest { ObjVer = working });
    version = checkedIn.ObjectInfo.LatestVersion.ObjectVersion.VersionInfo.Version.InternalVersion;
    Console.WriteLine($"Checked in: now version {version}");
}
catch
{
    // Do not leave the object checked out.
    await objects.UndoCheckoutAsync(new UndoCheckoutRequest
    {
        ObjVer = ObjVer(objId.Type, objId.ItemId.InternalId, workingVersion.InternalVersion),
    });
    throw;
}
```

*Source: [csharp/Recipes/UpdateProperties.cs](https://developer.m-files.com/APIs/gRPC-API/downloads/samples/csharp/Recipes/UpdateProperties.cs)*

### Go

```go
// One call: the server checks the object out, sets the values and checks it in.
// Name the version you read; with fail_if_newer_version_exists the call fails instead of
// overwriting a change someone else made after that version.
updated, err := objects.SetProperties(ctx, &mfiles.SetPropertiesRequest{
	ObjVer:                        mfilesclient.ObjVer(0, id, version),
	AllowModifyingCheckedInObject: true,
	FailIfNewerVersionExists:      true,
	// Other properties stay as they are (remove_unspecified_properties is false).
	Properties: []*mfiles.PropertyValue{
		mfilesclient.PropertyValue(1004, mfilesclient.Text("grpc, sample")), // Keywords
	},
})
if err != nil {
	return err
}
version = updated.GetObjectInfo().GetLatestVersion().GetObjectVersion().GetVersionInfo().
	GetVersion().GetInternalVersion()
fmt.Printf("Set Keywords: now version %d\n", version)
```

*Source: [go/recipes/update_properties/main.go](https://developer.m-files.com/APIs/gRPC-API/downloads/samples/go/recipes/update_properties/main.go)*

```go

// checkOutSetCheckIn makes several changes into one new version; nobody else can change the
// object meanwhile.
func checkOutSetCheckIn(ctx context.Context, objects mfiles.IRPCObjectOperationsClient,
	objID *mfiles.ObjID) error {
	checkedOut, err := objects.CheckOut(ctx, &mfiles.CheckOutRequest{ObjId: objID})
	if err != nil {
		return err
	}
	workingVersion := checkedOut.GetObjectInfo().GetObjectVersion().GetVersionInfo().GetVersion()
	fmt.Printf("Checked out: working version %d\n", workingVersion.GetInternalVersion())
	working := mfilesclient.ObjVer(objID.GetType(), objID.GetItemId().GetInternalId(),
		workingVersion.GetInternalVersion())

	today := time.Now().UTC()
	_, err = objects.SetProperties(ctx, &mfiles.SetPropertiesRequest{
		ObjVer: working,
		Properties: []*mfiles.PropertyValue{
			mfilesclient.PropertyValue(1004, mfilesclient.Text("grpc, sample, checked out")), // Keywords
			mfilesclient.PropertyValue(1002, // Document date
				mfilesclient.Date(today.Year(), today.Month(), today.Day())),
		},
	})
	var checkedIn *mfiles.CheckInResponse
	if err == nil {
		checkedIn, err = objects.CheckIn(ctx, &mfiles.CheckInRequest{ObjVer: working})
	}
	if err != nil {
		// Do not leave the object checked out.
		_, _ = objects.UndoCheckout(context.WithoutCancel(ctx),
			&mfiles.UndoCheckoutRequest{ObjVer: working})
		return err
	}
	fmt.Printf("Checked in: now version %d\n", checkedIn.GetObjectInfo().GetLatestVersion().
		GetObjectVersion().GetVersionInfo().GetVersion().GetInternalVersion())
	return nil
}

```

*Source: [go/recipes/update_properties/main.go](https://developer.m-files.com/APIs/gRPC-API/downloads/samples/go/recipes/update_properties/main.go)*

Output:

```text
Created [docs-test] Python update-properties (ID 612, version 1, modified 2026-10-31 14:55:57 UTC)
Set Keywords: now version 2
Checked out: working version 3
Checked in: now version 3
  Property 1002: 2026-10-31
  Property 1004: grpc, sample, checked out
Deleted object 0-612
```

The checked-out version keeps its number when it is checked in: the changes made while the
document was checked out became one version, 3.

## Pitfalls

* **`remove_unspecified_properties` true removes every property you did not send.** Leave it
  false unless you send the complete set.
* **A stale write fails** with `0x800400BB` "There is a newer version of this object on the
  server." when `fail_if_newer_version_exists` is true. Read the object again, reapply your
  change and retry. With the flag false, the same call succeeds and writes over the newer
  version's values.
* **A checked-in object** needs `allow_modifying_checked_in_object` true; without it the call
  fails with `0x800400B2` "The object is not checked out."
* **Comment (33) belongs to a version.** A comment set in one change is not carried to the next
  version.
* Several `SetProperties` calls on a checked-out object, then `CheckIn`, make one version, not
  one per call.
* If your program stops between `CheckOut` and `CheckIn`, the object stays checked out to you.
  Check it in, or undo the check-out with
  [UndoCheckout](https://developer.m-files.com/APIs/gRPC-API/Reference/MFiles.IRPCObjectOperations/UndoCheckout/index.md).

## See also

* [Objects and versions](https://developer.m-files.com/APIs/gRPC-API/concepts/objects-and-versions/index.md): versions and check-out.
* [Properties and values](https://developer.m-files.com/APIs/gRPC-API/concepts/properties-and-values/index.md): how to build each kind of value.
* [Change the workflow state](https://developer.m-files.com/APIs/gRPC-API/guides/workflow-state/index.md), which is also a property change.
