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.
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.
{
"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"
}
{
"@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"
]
}
}
}
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:
http://localhost:8080/api/2/things/my-namespace:my-thing/features/volume/inbox/messages/undefinedhttp://localhost:8080/api/2/things/my-namespace:my-thing/features/volume/inbox/messages/set-volumewithout bodyboth 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
volume feature-definition filtered through ditto