Skip to main content

Validate graphs

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

The basic syntax for the check graph command is:


_1
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

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

  • Check all predefined graphs in property.json:


    _1
    tman check graph --app /home/TEN-Agent/agents

  • Check a specific predefined graph:


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

  • Check a start_graph command:


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

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

The tman check graph command validates the following rules:

Nodes must be present

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

  • Example: No nodes defined


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

    Output:


    _5
    Checking graph[0]... ❌. Details:
    _5
    No extension node is defined in graph.
    _5
    _5
    All is done.
    _5
    ❌ Error: 1/1 graphs failed.

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


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

    Output:


    _5
    Checking graph[0]... ❌. Details:
    _5
    Duplicated extension was found in nodes[1], addon: basic_hello_world_1__test_extension, name: test_extension.
    _5
    _5
    All is done.
    _5
    ❌ Error: 1/1 graphs failed.

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.


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


    _1
    tman check graph --app /home/TEN-Agent/agents

    Output:


    _5
    Checking graph[0]... ❌. Details:
    _5
    The extension declared in connections[0] is not defined in nodes, extension_group: producer, extension: some_extension.
    _5
    _5
    All is done.
    _5
    ❌ Error: 1/1 graphs failed.

  • Example: Destination extension not defined

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


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


    _1
    tman check graph --app /home/TEN-Agent/agents

    Output:


    _5
    Checking graph[0]... ❌. Details:
    _5
    The extension declared in connections[0].cmd[1] is not defined in nodes extension_group: some_group, extension: consumer.
    _5
    _5
    All is done.
    _5
    ❌ Error: 1/1 graphs failed.

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.


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


    _1
    tman check graph --app /home/TEN-Agent/agents

    Output:


    _5
    Checking graph[0]... ❌. Details:
    _5
    The following packages are declared in nodes but not installed: [("localhost", Extension, "default_extension_go")].
    _5
    _5
    All is done.
    _5
    ❌ 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.


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


    _1
    tman check graph --app /home/TEN-Agent/agents

    Output:


    _5
    Checking graph[0]... ❌. Details:
    _5
    The following packages are declared in nodes but not installed: [("localhost", Extension, "default_extension_go")].
    _5
    _5
    All is done.
    _5
    ❌ Error: 1/1 graphs failed.

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.


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

    Output:


    _5
    Checking graph[0]... ❌. Details:
    _5
    extension 'some_extension' is defined in connection[0] and connection[1], merge them into one section.
    _5
    _5
    All is done.
    _5
    ❌ Error: 1/1 graphs failed.

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.


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

    Output:


    _7
    Checking graph[0]... ❌. Details:
    _7
    - connection[0]:
    _7
    - Merge the following cmd into one section:
    _7
    'hello' is defined in flow[0] and flow[1].
    _7
    _7
    All is done.
    _7
    ❌ Error: 1/1 graphs failed.

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.


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

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


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

    Check the graph with the following command.


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

    Output:


    _6
    Checking graph[0]... ❌. Details:
    _6
    - connections[0]:
    _6
    - cmd[0]: Schema incompatible to [extension_group: some_group, extension: another_ext], { .foo: type is incompatible, source is [string], but target is [int8] }
    _6
    _6
    All is done.
    _6
    ❌ Error: 1/1 graphs failed.

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.


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

    Output:


    _4
    ❌ Error: The graph json string is invalid
    _4
    _4
    Caused by:
    _4
    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.


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

    Output:


    _4
    ❌ Error: The graph json string is invalid
    _4
    _4
    Caused by:
    _4
    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.


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

    Output:


    _4
    ❌ Error: The graph json string is invalid
    _4
    _4
    Caused by:
    _4
    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.

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

    Check the graph using the following command.


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

    Output:


    _1
    ❌ 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.


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

    Output:


    _1
    ❌ 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'