# How to Resolve Conflicts During kcmd Push When Metadata Changed Remotely

> Learn to resolve kcmd push conflicts when remote metadata changes. Discover how to safely pull changes or use force to override errors in Google's knowledge catalog.

- Repository: [Google Cloud Platform/knowledge-catalog](https://github.com/GoogleCloudPlatform/knowledge-catalog)
- Tags: how-to-guide
- Published: 2026-07-14

---

**When `kcmd push` detects that remote metadata has changed, it aborts with a conflict error and requires you to run `kcmd pull` to reconcile differences, though you can override this with the `--force` flag.**

The `kcmd` CLI (Metadata-as-Code command line tool) in the GoogleCloudPlatform/knowledge-catalog repository synchronizes local YAML snapshot files with Google Knowledge Catalog. When multiple users edit metadata simultaneously, **resolving conflicts during kcmd push when metadata changed remotely** requires understanding the tool's checksum-based validation system to prevent accidental overwrites.

## How kcmd Detects Push Conflicts

The conflict detection in `kcmd` follows a **fast-fail strategy** designed to prevent data loss. Before modifying any remote entry, the tool validates the current state against your local snapshot to ensure the remote version has not diverged since your last pull.

### Checksum Validation Against `.catalog.state`

Each entry and aspect tracks a cryptographic checksum stored in the hidden state file **`.catalog.state`** located in your snapshot root. According to the specification in [`toolbox/mdcode/docs/spec.md`](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/toolbox/mdcode/docs/spec.md), this checksum represents the state of the metadata at the time of your last successful pull.

Before sending an update, `kcmd` looks up the current remote entry using `lookupEntry()` and compares your stored checksum against the remote version's checksum. If they differ, the push operation aborts immediately with a clear error message instructing you to run `kcmd pull` first.

### The Fast-Fail Mechanism in `CatalogSync.push()`

The conflict-handling logic resides in `CatalogSync.push()` within [`toolbox/mdcode/src/libts/sync.ts`](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/toolbox/mdcode/src/libts/sync.ts) (lines 82-115). The implementation performs the following validation:

```typescript
const exist = await this._catalog.lookupEntry(project, location, entry.name);
if (exist.status != 200 || !exist.result) { … }   // create new entry
// … build updateMask …
const res = await this._catalog.modifyEntry(project, location, entry, updateMask, aspectKeys);
if (res.status !== 200) {
  return { success: false, details: `Failed to update entry ${name}: ${res.message || res.status}` };
}

```

If `modifyEntry` returns a non-200 status—indicating the remote entry was modified since your last pull—the push fails and surfaces the conflict error to the user.

## The Conflict Resolution Workflow

When `kcmd` detects a checksum mismatch, you must reconcile the differences before pushing again. Follow this standard workflow:

1. Run `kcmd pull` to merge remote modifications into your local snapshot files.
2. Review and edit the merged YAML files (e.g., [`tables/my_dataset.my_table.yaml`](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/tables/my_dataset.my_table.yaml)) to resolve any semantic conflicts.
3. Execute `kcmd push` again, which will now succeed because your local checksum matches the remote state.

### Example Workflow

```bash

# 1️⃣ Pull the latest remote state into your local snapshot

kcmd pull

# 2️⃣ Edit a YAML file (e.g. tables/my_dataset.my_table.yaml) locally

# 3️⃣ Attempt to push changes

kcmd push

# → If the entry was modified remotely, you’ll see:

#   “Failed to update entry …: conflict detected – run `kcmd pull` first”

# 4️⃣ Resolve the conflict:

kcmd pull          # merges remote changes into the local file

# (edit the file again if needed)

kcmd push          # now succeeds

# 5️⃣ Force an update, ignoring a detected conflict

kcmd push --force

```

## Force Pushing and Dry Run Options

The CLI provides flags to either override conflict detection or preview changes before applying them.

### Overriding Conflicts with `--force`

The `--force` flag, defined in [`toolbox/mdcode/src/tool/commands.ts`](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/toolbox/mdcode/src/tool/commands.ts), allows you to apply local changes regardless of remote modifications. This bypasses the checksum validation in `CatalogSync.push()`:

```bash
kcmd push --force

```

Use this option with caution, as it will overwrite the remote metadata with your local version, potentially discarding changes made by other users.

### Previewing Changes with `--dry-run`

The `--dry-run` flag executes the entire validation logic—including checksum comparison and conflict detection—but stops short of calling `modifyEntry()` to apply changes. As documented in [`toolbox/mdcode/docs/plan.md`](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/toolbox/mdcode/docs/plan.md), this mode allows you to preview which entries would be affected:

```bash
kcmd push --dry-run

```

This simulates the push operation and reports which entries would be created, updated, or rejected due to conflicts, allowing you to verify your changes safely before risking a conflict error.

## Key Implementation Files

The conflict resolution system spans several critical files in the repository:

- **[`toolbox/mdcode/src/libts/sync.ts`](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/toolbox/mdcode/src/libts/sync.ts)**: Contains the core `CatalogSync.push()` implementation where `lookupEntry()` and `modifyEntry()` handle conflict detection.
- **[`toolbox/mdcode/docs/spec.md`](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/toolbox/mdcode/docs/spec.md)**: Defines the checksum storage specification and fast-fail conflict detection strategy.
- **[`toolbox/mdcode/src/tool/commands.ts`](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/toolbox/mdcode/src/tool/commands.ts)**: Defines CLI flags including `--force` and `--dry-run`.
- **`.catalog.state`**: The generated state file in your snapshot root that stores entry checksums for validation.

## Summary

- **Conflict detection** relies on checksum comparison between your local `.catalog.state` file and the remote entry state via `lookupEntry()`.
- **Fast-fail behavior**: When checksums mismatch, `kcmd push` aborts with an error instructing you to run `kcmd pull`.
- **Resolution workflow**: Always pull remote changes, resolve conflicts locally, then push again.
- **Override options**: Use `--force` to bypass conflicts or `--dry-run` to preview changes without modifying the catalog.
- **Core implementation**: The logic resides in `CatalogSync.push()` at lines 82-115 of [`toolbox/mdcode/src/libts/sync.ts`](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/toolbox/mdcode/src/libts/sync.ts).

## Frequently Asked Questions

### What triggers a conflict error during kcmd push?

A conflict occurs when the checksum stored in your local `.catalog.state` file does not match the current checksum of the remote entry in Google Knowledge Catalog. This indicates that someone else modified the metadata after your last pull, causing the `modifyEntry()` call in [`toolbox/mdcode/src/libts/sync.ts`](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/toolbox/mdcode/src/libts/sync.ts) to return a non-200 status and abort the push operation.

### Can I push local changes without pulling first?

Yes, but only by using the `--force` flag. This overrides the checksum validation in `CatalogSync.push()` and allows `modifyEntry()` to proceed regardless of remote changes. However, forcing a push will overwrite the remote metadata with your local version, potentially losing changes made by other users.

### What is the `.catalog.state` file used for?

The `.catalog.state` file is a hidden metadata file generated in your snapshot root that stores cryptographic checksums for each entry and aspect. It represents the "known good" state of the remote catalog at the time of your last successful pull, enabling `kcmd` to detect when remote changes have occurred by comparing these stored values against current remote checksums retrieved via `lookupEntry()`.

### How can I preview what kcmd push will do before running it?

Use the `--dry-run` flag when executing `kcmd push`. This mode runs through the entire validation logic—including checksum comparison and conflict detection—but stops before actually calling `modifyEntry()` to apply changes. It reports which entries would be created, updated, or rejected due to conflicts, allowing you to verify your changes safely without modifying the remote catalog.