# Validate graphs (/en/ai/ten-agent/develop/validate-graphs)

> For AI agents: see the complete documentation index at [llms.txt](/llms.txt).

Graph validation is essential for preventing runtime errors in TEN applications. Invalid graph configurations can cause extension connection failures, message routing errors, schema compatibility issues, and missing dependency problems.

Use the `tman check graph` command to validate TEN app graphs and catch these issues before deployment. This command verifies that:

* All required nodes are defined
* Extension connections are valid
* Message schemas are compatible
* Required packages are installed

Validation helps ensure your TEN app graphs function correctly when deployed.

## Command syntax [#command-syntax]

The basic syntax for the `check graph` command is:

```bash
tman check graph --app APP_PATH [OPTIONS]
```

The command uses the following key parameters:

* `--app APP_PATH`: The absolute path to the app directory containing graph definitions

* `--predefined-graph-name GRAPH_NAME`: Validate a specific predefined graph by name. If omitted, all predefined graphs in the app are validated. (Optional)

* `--graph JSON_STRING`: Validate a JSON string representing a `start_graph` command instead of predefined graphs from files. (Optional)

Follow these guidelines when using the command:

* Run the command from any directory—you don't need to be in the app's root directory
* Use the command to validate connections that span multiple apps in multi-app graphs

### Usage examples [#usage-examples]

The following examples illustrate the use of the `tman check graph` command:

* **Check all predefined graphs in `property.json`**:

  ```bash
  tman check graph --app /home/TEN-Agent/agents
  ```

* **Check a specific predefined graph**:

  ```bash
  tman check graph --predefined-graph-name va.openai.azure --app /home/TEN-Agent/agents
  ```

* **Check a `start_graph` command**:

  ```bash
  tman check graph --graph '{
  "type": "start_graph",
  "seq_id": "55",
  "nodes": [
      {
      "type": "extension",
      "name": "test_extension",
      "addon": "basic_hello_world_2__test_extension",
      "extension_group": "test_extension_group",
      "app": "msgpack://127.0.0.1:8001/"
      },
      {
      "type": "extension",
      "name": "test_extension",
      "addon": "basic_hello_world_1__test_extension",
      "extension_group": "test_extension_group",
      "app": "msgpack://127.0.0.1:8001/"
      }
  ]
  }' --app /home/TEN-Agent/agents
  ```

## Requirements and setup [#requirements-and-setup]

Before using `check graph`, ensure the following requirements are met:

* **Package installation**: All extensions that the app depends on must be installed using `tman install`. The validation process requires information about each extension in the graph, such as APIs defined in their `manifest.json` files.

* **Predefined graph definition**: If you specify a predefined graph name, the definition must exist in the `property.json` file of the app specified by the `--app` parameter.

* **Unique app URI**: In multi-app graphs, each app's `property.json` must define a unique `ten::uri`. The `uri` value cannot be set to `"localhost"`.

## Validation rules [#validation-rules]

The `tman check graph` command validates the following rules:

### Nodes must be present [#nodes-must-be-present]

The `nodes` array is required in any graph definition. If absent, an error is thrown.

* **Example: No nodes defined**

  ```bash
  tman check graph --graph '{
    "type": "start_graph",
    "seq_id": "55",
    "nodes": []
  }' --app /home/TEN-Agent/agents
  ```

  **Output**:

  ```text
  Checking graph[0]... ❌. Details:
    No extension node is defined in graph.

  All is done.
  ❌  Error: 1/1 graphs failed.
  ```

### Node names must be unique [#node-names-must-be-unique]

Each node in the `nodes` array represents an extension instance within a group of an app, created by a specified addon. Each extension instance must be uniquely represented by a single node. A node is uniquely identified by the combination of `app`, `extension_group`, and `name`. Multiple entries for the same extension instance are not allowed.

* **Example: Duplicate nodes**

  ```bash
  tman check graph --graph '{
    "type": "start_graph",
    "seq_id": "55",
    "nodes": [
      {
        "type": "extension",
        "name": "test_extension",
        "addon": "basic_hello_world_2__test_extension",
        "extension_group": "test_extension_group",
        "app": "msgpack://127.0.0.1:8001/"
      },
      {
        "type": "extension",
        "name": "test_extension",
        "addon": "basic_hello_world_1__test_extension",
        "extension_group": "test_extension_group",
        "app": "msgpack://127.0.0.1:8001/"
      }
    ]
  }' --app /home/TEN-Agent/agents
  ```

  **Output**:

  ```text
  Checking graph[0]... ❌. Details:
    Duplicated extension was found in nodes[1], addon: basic_hello_world_1__test_extension, name: test_extension.

  All is done.
  ❌  Error: 1/1 graphs failed.
  ```

### Connection extensions must be defined in nodes [#connection-extensions-must-be-defined-in-nodes]

All extension instances referenced in the `connections` field, whether as a source or destination, must be explicitly defined in the `nodes` field. Any instance not defined in the `nodes` array causes validation errors.

* **Example: Source extension not defined**

  Suppose that the `property.json` file of a TEN app is as follows.

  ```json
  {
    "ten": {
      "predefined_graphs": [
        {
          "name": "default",
          "auto_start": false,
          "nodes": [
            {
              "type": "extension",
              "name": "some_extension",
              "addon": "default_extension_go",
              "extension_group": "some_group"
            }
          ],
          "connections": [
            {
              "extension": "some_extension",
              "cmd": [
                {
                  "name": "hello",
                  "dest": [
                    {
                      "extension": "some_extension"
                    }
                  ]
                }
              ]
            }
          ]
        }
      ]
    }
  }
  ```

  ```bash
  tman check graph --app /home/TEN-Agent/agents
  ```

  **Output**:

  ```text
  Checking graph[0]... ❌. Details:
    The extension declared in connections[0] is not defined in nodes, extension_group: producer, extension: some_extension.

  All is done.
  ❌  Error: 1/1 graphs failed.
  ```

* **Example: Destination extension not defined**

  Suppose that the `property.json` file of a TEN app is as follows.

  ```json
  {
    "ten": {
      "predefined_graphs": [
        {
          "name": "default",
          "auto_start": false,
          "nodes": [
            {
              "type": "extension",
              "name": "some_extension",
              "addon": "default_extension_go",
              "extension_group": "some_group"
            },
            {
              "type": "extension",
              "name": "some_extension_1",
              "addon": "default_extension_go",
              "extension_group": "some_group"
            }
          ],
          "connections": [
            {
              "extension": "some_extension",
              "cmd": [
                {
                  "name": "hello",
                  "dest": [
                    {
                      "extension": "some_extension_1"
                    }
                  ]
                },
                {
                  "name": "world",
                  "dest": [
                    {
                      "extension": "some_extension_1"
                    },
                    {
                      "extension": "consumer"
                    }
                  ]
                }
              ]
            }
          ]
        }
      ]
    }
  }
  ```

  ```bash
  tman check graph --app /home/TEN-Agent/agents
  ```

  **Output**:

  ```text
  Checking graph[0]... ❌. Details:
    The extension declared in connections[0].cmd[1] is not defined in nodes extension_group: some_group, extension: consumer.

  All is done.
  ❌  Error: 1/1 graphs failed.
  ```

### Node addons must be installed [#node-addons-must-be-installed]

All node addons must be installed using `tman install` and have matching app URIs for successful validation.

* **Example: The `ten::uri` in `property.json` is not equal to the `app` field in nodes**:

  Suppose that the `property.json` file of a TEN app is as follows.

  ```json
  {
    "ten": {
      "predefined_graphs": [
        {
          "name": "default",
          "auto_start": false,
          "nodes": [
            {
              "type": "extension",
              "name": "some_extension",
              "addon": "default_extension_go",
              "extension_group": "some_group"
            }
          ]
        }
      ],
      "uri": "http://localhost:8001"
    }
  }
  ```

  ```bash
  tman check graph --app /home/TEN-Agent/agents
  ```

  **Output**:

  ```text
  Checking graph[0]... ❌. Details:
    The following packages are declared in nodes but not installed: [("localhost", Extension, "default_extension_go")].

  All is done.
  ❌  Error: 1/1 graphs failed.
  ```

  The problem is that all packages in the app are stored in a map for which the key is the `uri` of the app, and each node in the graph is retrieved by the `app` field (`localhost` by default). The `app` in node (`localhost`) is a mismatch with the `uri` of the app (`http://localhost:8001`).

* **Example: The `ten_packages` does not exist as `tman install` has not been executed**

  Suppose that the `property.json` file of a TEN app is as follows and the `ten_packages` directory does **NOT** exist.

  ```json
  {
    "ten": {
      "predefined_graphs": [
        {
          "name": "default",
          "auto_start": false,
          "nodes": [
            {
              "type": "extension",
              "name": "some_extension",
              "addon": "default_extension_go",
              "extension_group": "some_group"
            }
          ]
        }
      ]
    }
  }
  ```

  ```bash
  tman check graph --app /home/TEN-Agent/agents
  ```

  **Output**:

  ```text
  Checking graph[0]... ❌. Details:
    The following packages are declared in nodes but not installed: [("localhost", Extension, "default_extension_go")].

  All is done.
  ❌  Error: 1/1 graphs failed.
  ```

### Extension connections must be in one section [#extension-connections-must-be-in-one-section]

All messages sent from an extension must be defined within a single connection section. Multiple connection sections for the same extension are not allowed.

* **Example**:

  Suppose that all the packages have been installed.

  ```bash
  tman check graph --graph '{
    "nodes": [
      {
        "type": "extension",
        "name": "some_extension",
        "addon": "default_extension_go",
        "extension_group": "some_group"
      },
      {
        "type": "extension",
        "name": "another_ext",
        "addon": "default_extension_go",
        "extension_group": "some_group"
      }
    ],
    "connections": [
      {
        "extension": "some_extension",
        "cmd": [
          {
            "name": "hello",
            "dest": [
              {
                "extension": "another_ext"
              }
            ]
          }
        ]
      },
      {
        "extension": "some_extension",
        "cmd": [
          {
            "name": "hello_2",
            "dest": [
              {
                "extension": "another_ext"
              }
            ]
          }
        ]
      }
    ]
  }' --app /home/TEN-Agent/agents
  ```

  **Output**:

  ```text
  Checking graph[0]... ❌. Details:
    extension 'some_extension' is defined in connection[0] and connection[1], merge them into one section.

  All is done.
  ❌  Error: 1/1 graphs failed.
  ```

### Message names must be unique within each type [#message-names-must-be-unique-within-each-type]

Each message sent from an extension must have a unique name within its message type (cmd, data, etc.). Duplicate message names within the same type are not allowed.

* **Example**:

  Suppose that all the packages have been installed.

  ```bash
  tman check graph --graph '{
    "nodes": [
      {
        "type": "extension",
        "name": "some_extension",
        "addon": "addon_a",
        "extension_group": "some_group"
      },
      {
        "type": "extension",
        "name": "another_ext",
        "addon": "addon_b",
        "extension_group": "some_group"
      }
    ],
    "connections": [
      {
        "extension": "some_extension",
        "cmd": [
          {
            "name": "hello",
            "dest": [
              {
                "extension": "another_ext"
              }
            ]
          },
          {
            "name": "hello",
            "dest": [
              {
                "extension": "some_extension"
              }
            ]
          }
        ]
      }
    ]
  }' --app /home/TEN-Agent/agents
  ```

  **Output**:

  ```text
  Checking graph[0]... ❌. Details:
    - connection[0]:
      - Merge the following cmd into one section:
        'hello' is defined in flow[0] and flow[1].

  All is done.
  ❌  Error: 1/1 graphs failed.
  ```

### Message schemas must be compatible [#message-schemas-must-be-compatible]

Messages are validated for schema compatibility based on the schema definitions in the `manifest.json` files of extensions. Validation follows these compatibility rules:

* If the message schema is not found in either the source or target extension, the message is compatible

* If the message schema is only found in one extension, the message is incompatible

* If schemas exist in both extensions, the message is compatible only when:
  * Property types are compatible
  * For object properties, all fields in both source and target schemas must have compatible types
  * If the target schema defines `required` fields, the source schema must also define `required` fields that include all target requirements

* **Example**:

  Suppose that all the packages have been installed.

  The `manifest.json` file for `addon_a` is as follows.

  ```json
  {
    "type": "extension",
    "name": "addon_a",
    "version": "0.1.0",
    "dependencies": [
      {
        "type": "system",
        "name": "ten_runtime_go",
        "version": "0.1.0"
      }
    ],
    "package": {
      "include": ["**"]
    },
    "api": {
      "cmd_out": [
        {
          "name": "cmd_1",
          "property": {
            "foo": {
              "type": "string"
            }
          }
        }
      ]
    }
  }
  ```

  And, the `manifest.json` file for `addon_b` is as follows.

  ```json
  {
    "type": "extension",
    "name": "addon_b",
    "version": "0.1.0",
    "dependencies": [
      {
        "type": "system",
        "name": "ten_runtime_go",
        "version": "0.1.0"
      }
    ],
    "package": {
      "include": ["**"]
    },
    "api": {
      "cmd_in": [
        {
          "name": "cmd_1",
          "property": {
            "foo": {
              "type": "int8"
            }
          }
        }
      ]
    }
  }
  ```

  Check the graph with the following command.

  ```bash
  tman check graph --graph '{
    "nodes": [
      {
        "type": "extension",
        "name": "some_extension",
        "addon": "addon_a",
        "extension_group": "some_group"
      },
      {
        "type": "extension",
        "name": "another_ext",
        "addon": "addon_b",
        "extension_group": "some_group"
      }
    ],
    "connections": [
      {
        "extension": "some_extension",
        "cmd": [
          {
            "name": "cmd_1",
            "dest": [
              {
                "extension": "another_ext"
              }
            ]
          }
        ]
      }
    ]
  }' --app /home/TEN-Agent/agents
  ```

  **Output**:

  ```text
  Checking graph[0]... ❌. Details:
    - connections[0]:
      - cmd[0]:  Schema incompatible to [extension_group: some_group, extension: another_ext], { .foo: type is incompatible, source is [string], but target is [int8] }

  All is done.
  ❌ Error: 1/1 graphs failed.
  ```

### App fields must be unambiguous [#app-fields-must-be-unambiguous]

The `app` field in each node must follow specific rules to ensure proper app identification and routing.

**App field requirements:**

* Must equal the `ten::uri` of the corresponding TEN app

* Either all nodes must have `app` declared, or none should

* Cannot be set to `localhost`

* Cannot be an empty string

* **Example: Some nodes specify the `app` field**

  Check the graph with the following command.

  ```bash
  tman check graph --graph '{
    "nodes": [
      {
        "type": "extension",
        "name": "some_extension",
        "addon": "addon_a",
        "extension_group": "some_group"
      },
      {
        "type": "extension",
        "name": "another_ext",
        "addon": "addon_b",
        "extension_group": "some_group",
        "app": "http://localhost:8000"
      }
    ]
  }' --app /home/TEN-Agent/agents
  ```

  **Output**:

  ```text
  ❌  Error: The graph json string is invalid

  Caused by:
    Either all nodes should have 'app' declared, or none should, but not a mix of both.
  ```

* **Example: Source extension specifies `app` in connections when nodes don't**

  Check the graph using the following command.

  ```bash
  tman check graph --graph '{
    "nodes": [
      {
        "type": "extension",
        "name": "some_extension",
        "addon": "addon_a",
        "extension_group": "some_group"
      },
      {
        "type": "extension",
        "name": "another_ext",
        "addon": "addon_b",
        "extension_group": "some_group"
      }
    ],
    "connections": [
      {
        "extension": "some_extension",
        "app": "http://localhost:8000",
        "cmd": [
          {
            "name": "cmd_1",
            "dest": [
              {
                "extension": "another_ext"
              }
            ]
          }
        ]
      }
    ]
  }' --app /home/TEN-Agent/agents
  ```

  **Output**:

  ```text
  ❌  Error: The graph json string is invalid

  Caused by:
    connections[0].the 'app' should not be declared, as not any node has declared it
  ```

* **Example: Target extension specifies `app` in connections when nodes don't**

  Check the graph using the following command.

  ```bash
  tman check graph --graph '{
    "nodes": [
      {
        "type": "extension",
        "name": "some_extension",
        "addon": "addon_a",
        "extension_group": "some_group"
      },
      {
        "type": "extension",
        "name": "another_ext",
        "addon": "addon_b",
        "extension_group": "some_group"
      }
    ],
    "connections": [
      {
        "extension": "some_extension",
        "cmd": [
          {
            "name": "cmd_1",
            "dest": [
              {
                "extension": "another_ext",
                "app": "http://localhost:8000"
              }
            ]
          }
        ]
      }
    ]
  }' --app /home/TEN-Agent/agents
  ```

  **Output**:

  ```text
  ❌  Error: The graph json string is invalid

  Caused by:
    connections[0].cmd[0].dest[0]: the 'app' should not be declared, as not any node has declared it
  ```

* **Example: App field doesn't match ten::uri**

  Same as the example for [Node addons must be installed](#node-addons-must-be-installed).

* **Example: App field is `localhost` in a single-app graph**

  Check the graph using the following command.

  ```bash
  tman check graph --graph '{
    "nodes": [
      {
        "type": "extension",
        "name": "some_extension",
        "addon": "addon_a",
        "extension_group": "some_group"
      },
      {
        "type": "extension",
        "name": "another_ext",
        "addon": "addon_b",
        "extension_group": "some_group",
        "app": "localhost"
      }
    ],
    "connections": [
      {
        "extension": "some_extension",
        "cmd": [
          {
            "name": "cmd_1",
            "dest": [
              {
                "extension": "another_ext"
              }
            ]
          }
        ]
      }
    ]
  }' --app /home/TEN-Agent/agents
  ```

  **Output**:

  ```text
  ❌  Error: Failed to parse graph string, nodes[1]: 'localhost' is not allowed in graph definition, and the graph seems to be a single-app graph, just remove the 'app' field
  ```

* **Example: App field is `localhost` in a multi-app graph**

  Check the graph using the following command.

  ```bash
  tman check graph --graph '{
    "nodes": [
      {
        "type": "extension",
        "name": "some_extension",
        "addon": "addon_a",
        "extension_group": "some_group",
        "app": "http://localhost:8000"
      },
      {
        "type": "extension",
        "name": "another_ext",
        "addon": "addon_b",
        "extension_group": "some_group",
        "app": "localhost"
      }
    ],
    "connections": [
      {
        "extension": "some_extension",
        "app": "http://localhost:8000",
        "cmd": [
          {
            "name": "cmd_1",
            "dest": [
              {
                "extension": "another_ext"
              }
            ]
          }
        ]
      }
    ]
  }' --app /home/TEN-Agent/agents
  ```

  **Output**:

  ```text
  ❌  Error: Failed to parse graph string, nodes[1]: 'localhost' is not allowed in graph definition, change the content of 'app' field to be consistent with 'ten::uri'
  ```
