Skip to content

WoT model based message validation not failing an invalid "fire-and-forget" request #2392

@Laures

Description

@Laures

I created a thing based on a thing definition, the thing has a feature called "volume" with its own definition shown below. Based on the documentation i expected ditto to block all attempts to send non-defined or incomplete messages to the things inbox.

For example:

  • an attempt to send http://localhost:8080/api/2/things/my-namespace:my-thing/features/volume/inbox/messages/undefined
  • an attempt to send http://localhost:8080/api/2/things/my-namespace:my-thing/features/volume/inbox/messages/set-volume without body

both should result in a validation error. They do not.
Other validation features (like setting properties that are not defined) work as expected.

I tried to set a validation config but that did not change anything.

/devops/wot/config

{
    "configId": "ditto:global",
    "enabled": true,
    "thing": {
        "enforce": {
            "thing-description-modification": true,
            "attributes": true,
            "inbox-messages-input": true,
            "inbox-messages-output": true,
            "outbox-messages": true
        },
        "forbid": {
            "non-modeled-inbox-messages": true,
            "non-modeled-outbox-messages": true
        }
    },
    "feature": {
        "enforce": {
            "feature-description-modification": true,
            "presence-of-modeled-features": true
        },
        "forbid": {
            "feature-description-deletion": true,
            "non-modeled-outbox-messages": true
        }
    },
    "_revision": 1,
    "_created": "2026-04-02T08:15:12.852625643Z",
    "_modified": "2026-04-02T08:15:12.852625643Z"
}

volume feature-definition filtered through ditto

{
  "@context": [
    "https://www.w3.org/2022/wot/td/v1.1",
    {
      "om2": "http://www.ontology-of-units-of-measure.org/resource/om-2/",
      "time": "http://www.w3.org/2006/time#"
    }
  ],
  "title": "Volume",
  "description": "Volume Control.",
  "@type": "Thing",
  "id": "urn:/my-namespace:my-thing/features/volume",
  "base": "http://localhost:8080/api/2/things/my-namespace:my-thing/features/volume/",
  "version": {
    "model": "1.0.1",
    "instance": "1.0.1"
  },
  "links": [
    {
      "rel": "collection",
      "href": "http://localhost:8080/api/2/things/my-namespace:my-thing/",
      "type": "application/td+json"
    },
    {
      "rel": "type",
      "href": "https://my-public-server.de/wot/features/myThing-volume-1.0.1.tm.jsonld",
      "type": "application/tm+json"
    }
  ],
  "security": "basic_sc",
  "securityDefinitions": {
    "basic_sc": {
      "in": "header",
      "scheme": "basic"
    }
  },
  "support": "https://www.eclipse.dev/ditto/",
  "created": "2026-04-02T08:28:35.662122963Z",
  "forms": [
    {
      "op": "readallproperties",
      "href": "properties",
      "htv:methodName": "GET",
      "contentType": "application/json",
      "additionalResponses": [
        {
          "success": false,
          "schema": "dittoError"
        }
      ]
    },
    {
      "op": "readmultipleproperties",
      "href": "properties",
      "htv:methodName": "GET",
      "contentType": "application/json",
      "additionalResponses": [
        {
          "success": false,
          "schema": "dittoError"
        }
      ]
    },
    {
      "op": "writeallproperties",
      "href": "properties",
      "htv:methodName": "PUT",
      "contentType": "application/json",
      "additionalResponses": [
        {
          "success": false,
          "schema": "dittoError"
        }
      ]
    },
    {
      "op": "writemultipleproperties",
      "href": "properties",
      "htv:methodName": "PATCH",
      "contentType": "application/merge-patch+json",
      "additionalResponses": [
        {
          "success": false,
          "schema": "dittoError"
        }
      ]
    },
    {
      "op": [
        "observeallproperties",
        "unobserveallproperties"
      ],
      "href": "properties",
      "htv:methodName": "GET",
      "subprotocol": "sse",
      "contentType": "text/event-stream",
      "additionalResponses": [
        {
          "success": false,
          "schema": "dittoError"
        }
      ]
    },
    {
      "op": [
        "subscribeallevents",
        "unsubscribeallevents"
      ],
      "href": "outbox/messages",
      "htv:methodName": "GET",
      "subprotocol": "sse",
      "contentType": "text/event-stream",
      "additionalResponses": [
        {
          "success": false,
          "schema": "dittoError"
        }
      ]
    }
  ],
  "properties": {
    "volumeLevel": {
      "title": "Volume Level",
      "type": "integer",
      "minimum": 0,
      "maximum": 9,
      "observable": true,
      "forms": [
        {
          "op": "readproperty",
          "href": "properties/volumeLevel",
          "htv:methodName": "GET",
          "contentType": "application/json",
          "additionalResponses": [
            {
              "success": false,
              "schema": "dittoError"
            }
          ]
        },
        {
          "op": "writeproperty",
          "href": "properties/volumeLevel",
          "htv:methodName": "PUT",
          "contentType": "application/json",
          "additionalResponses": [
            {
              "success": false,
              "schema": "dittoError"
            }
          ]
        },
        {
          "op": "writeproperty",
          "href": "properties/volumeLevel",
          "htv:methodName": "PATCH",
          "contentType": "application/merge-patch+json",
          "additionalResponses": [
            {
              "success": false,
              "schema": "dittoError"
            }
          ]
        },
        {
          "op": [
            "observeproperty",
            "unobserveproperty"
          ],
          "href": "properties/volumeLevel",
          "htv:methodName": "GET",
          "subprotocol": "sse",
          "contentType": "text/event-stream",
          "additionalResponses": [
            {
              "success": false,
              "schema": "dittoError"
            }
          ]
        }
      ]
    }
  },
  "actions": {
    "set-volume": {
      "title": "Set Volume",
      "description": "Sets the audio volume.",
      "input": {
        "properties": {
          "volumeLevel": {
            "title": "Volume Level",
            "type": "integer",
            "minimum": 0,
            "maximum": 9
          }
        }
      },
      "synchronous": true,
      "forms": [
        {
          "op": "invokeaction",
          "href": "inbox/messages/set-volume",
          "htv:methodName": "POST",
          "contentType": "application/json",
          "additionalResponses": [
            {
              "success": false,
              "schema": "dittoError"
            }
          ]
        }
      ]
    }
  },
  "schemaDefinitions": {
    "dittoError": {
      "type": "object",
      "title": "Ditto error.",
      "description": "Provides additional information about an occurred error and how to resolve it.",
      "properties": {
        "status": {
          "type": "integer",
          "title": "Status code.",
          "description": "The status code of the error with HTTP status code semantics (e.g.: 4xx for user errors, 5xx for server errors).",
          "minimum": 400,
          "maximum": 599
        },
        "href": {
          "type": "string",
          "title": "Error link.",
          "description": "A link to further information about the error and how to fix it.",
          "format": "uri"
        },
        "message": {
          "type": "string",
          "title": "Error message.",
          "description": "The human readable message that explains what went wrong during the execution of a command/message."
        },
        "error": {
          "type": "string",
          "title": "Error code identifier.",
          "description": "The error code or identifier that uniquely identifies the error."
        },
        "description": {
          "type": "string",
          "title": "Error description.",
          "description": "Contains further information about the error e.g. a hint what caused the problem and how to solve it."
        }
      },
      "required": [
        "status",
        "error",
        "message"
      ]
    }
  }
}

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

Status

Done

Relationships

None yet

Development

No branches or pull requests

Issue actions