Table of Contents

Generation message level configuration

The level of some messages emitted by the Neos generator is configurable.
These messages appear like this in the output of the neos generate command:

{Time} {MessageLevel} {MessageCode}:{ElementIdentifier} - {Message}

You can disable them globally with the GenerationLogLevels property in the cluster configuration:

GenerationLogLevels:
  {MessageCode}: None

It is also possible to change the log level:

GenerationLogLevels:
  {MessageCode}: Information
Warning

We advise you to never use this feature to reduce the severity level of a message.

If you judge that on a given element the message is not justified (a rule does not always apply to 100% of cases), it is possible to customize the log level only for this element.

In Neos Studio, you must go to the properties of the module containing the element and activate the Generation message level configuration tab. From this screen, you can configure the log level by indicating {MessageCode} and {ElementIdentifier} as well as a justification.

UI template references

UI template generation validates every reference to a UI view, an image, a menu, a lookup, a string resource, a constant, a style class, or a UI component:

  • it must point to an element that exists,
  • the referenced element's module must be a declared module dependency of the template's module,
  • if the referenced element is Internal, the template's module must be granted access — see Module accessibility.

The two module checks have their own message codes, both warnings by default:

  • M0105 (UITemplateReferencesUnassociatedModule) — the referenced element's module is not a declared ModuleAssociation dependency of the template's module. For a UI component, its module must be the template's module or one of its parent modules. Declare the missing dependency, or reference an element of a module already associated.
  • M0106 (UITemplateReferencesUnauthorizedInternalElement) — the referenced element is Internal and its module has not granted access to the template's module. Grant InternalAccessGrantedTo, or make the element Public if it is meant to be broadly reusable.

They are the UI template counterparts of M0091 and M0090 below. A missing image, menu or style class is reported under the generic M0058 code of the UI template warnings. A missing UI view, lookup, string resource or constant is a generation error, which has no message code and cannot be configured.

.NET type references across modules

A metadata property that references an arbitrary .NET type by name (for example a DataObjectProperty.DotNetDataType, or a ProgrammableObjectParameter) is free text, so neos generate validates it on two independent axes:

  • M0090 — the referenced type is Internal and its module has not granted access to the referencing module. Fix the same way as an Internal-accessibility violation elsewhere: grant InternalAccessGrantedTo, or make the type Public if it is meant to be broadly reusable.
  • M0091 — the referenced type's module is not a declared ModuleAssociation dependency of the referencing module, regardless of Accessibility. Declare the missing dependency, or, if the two modules would then depend on each other in both directions, reconsider which module should actually own the referenced type.

Covers DataObject, Interface, EnumType, ConstantsStaticClass, Notification, ProgrammableObject, Entity, EntityView, UIView, and UIComponent — a smaller set than the transpiled-UI-C# [Origin] check (no ServerMethod, UISharedMethod, Lookup, Theme, Image, Report, or ReportStyle).

.NET compilation diagnostics

neos generate builds several scaffolding projects internally (CSharpAbstractions, AspNetCore, TaskRunner). When one of them fails to compile, the individual dotnet build diagnostics are parsed and reported one by one, deduplicated across the internal builds that can overlap on the same generated files:

  • M0092 (DotNetCompilationError) — a real .NET compilation error, shown by default (like any code, its level can be reconfigured through GenerationLogLevels or a per-element override — see the warning above).
  • M0093 (DotNetCompilationWarning) — a compilation warning, hidden by default like other diagnostics of this kind; enable it through GenerationLogLevels or a per-element override if you need to see it.

A diagnostic with a source position (file(line,col)) is reported with that file/line/column; one without a position (a NuGet restore failure, or a lower-level MSBuild/compiler error) is still reported and coded, just without a position.

The full raw output of the underlying dotnet build process is not shown by default anymore (it used to be logged in full for every failing build, which produced duplicate, uncoded log entries). It is still captured at the Verbose log level, so if a coded diagnostic alone isn't enough to diagnose a failure, rerun with neos [log:verbose] generate (or [log:debug]) to see it.

If the build process exits with an error but none of its output could be recognized as an individual diagnostic (an unexpected tool crash, for example), the raw output is still logged as an error by default, exactly as it was before this change — a build failure is never silently dropped, even in that case.

Indexes on columns stored as JSON

LocalizableString, Json and StringArray columns are stored as JSON and cannot be indexed directly, neither as a key column nor as an included column.

  • M0097 (IndexOnJsonColumn) — a warning, raised by neos generate for every index containing a column stored as JSON. It does not stop the generation, so existing clusters keep generating.

Neos Studio rejects such an index when saving the data table, and rejects an alternate key containing a property stored as JSON (a LocalizableString or StringArray property, or a String property bound to a Json column) when saving the entity (an alternate key generates a unique index). To filter, sort or search one language of a LocalizableString efficiently, index a computed column bound to that language instead — see Filter one language of a LocalizableString.

Empty keys on non-editable references

  • M0099 (EmptyKeyOnNonEditableReference) — a warning, raised by neos generate when UI view client code sets a server-generated key (auto-incremented integer, GUID or optional string key) of a reference whose entity view reference does not have HasEditableProperties to an empty value (for example order.ShippingAddress.Id = 0). On an editable reference, an empty key creates a new record on save. On a non-editable one, the server only looks for the existing record with this key, so the save fails. Setting the key to a real value, or assigning another instance to the reference itself, is not reported. Assignments made through a local variable pointing to the reference are not detected. The code editor of Neos Studio reports the same warning under the EMPTY_KEY_ON_NON_EDITABLE_REFERENCE code. See Creating a record through a reference.

Dead letter events of Pub/Sub subscriptions

  • M0100 (DeadLetterTopicShouldDifferFromPubSubEventName) — an error, raised by neos generate when a server method subscribed to a Pub/Sub event uses the subscribed event name as dead letter event name. A message failing on this subscription would be republished to the same subscription endlessly, so the dead letter event is ignored. See Retries and dead letter event.

Sensitive data not masked

  • M0101 (SensitivePropertyShouldBeMasked) — an information message by default, raised by neos generate for every String entity property marked as personal data (PersonalData) or encrypted (IsEncrypted) that has no masking type. Unless masked, its value is sent in clear to every user who can read it. Key properties are not reported, since a key cannot be masked. Many personal data, such as names, are meant to be shown, so the message does not fail any build. A cluster that wants to review its sensitive data raises it to Warning in GenerationLogLevels: it is then counted with the other warnings, and fails the generation run with --warnaserror, or at the Error level. Set a masking type on the property, or lower the level of this message when the value can be shown.
  • M0102 (MaskedPropertyShouldBeEncrypted) — a warning, raised by neos generate for every masked entity property that is not encrypted (IsEncrypted) and is stored in a column of the database, on a cluster with a database persistence. The mask only hides the value in the responses of the application: the value stays readable in the database. Expression properties and properties stored in no table are not reported. A property declared by an abstract entity without a table is reported once, with that entity, when a derived entity stores it. Encrypt the property, or lower the level of this message when the stored value needs no protection.

Module attribution

Both neos generate and neos check-metadata accept an --include-module option (disabled by default). When enabled, each diagnostic is tagged with the Neos module considered responsible for it, at the most precise level available:

  • when the diagnostic concerns a specific property whose value comes from a YAML override, the tag names the module that authored the currently active override — not just the module that originally declared the element;
  • otherwise, it falls back to the element's own owning module.

--include-module only controls whether this resolution runs at all — it exists because computing it has a cost, so it stays opt-in rather than always-on.

Note

The module is carried as a structured log property (Module), never inserted into the diagnostic's message text. It is therefore not visible in the default, human-readable console output, regardless of whether --include-module is set. To see it, enable JSON console output (set the Serilog:JsonOutputInConsole configuration value to true, for example via the Serilog__JsonOutputInConsole environment variable) — each diagnostic then appears as one JSON object per line, with a Module property when one was resolved:

{"Level":"WRN","SourceContext":"MetadataCheck","Message":"EntityProperty.Employee.JobId - Documentation defines the main language 'en' but is missing secondary languages: fr.","Module":"Party"}

A diagnostic with no single identifiable owning module (a cluster-wide summary line, or a violation that genuinely involves two modules with no clear "at fault" side) carries no Module property at all, rather than an arbitrary or misleading value.

This combination — --include-module plus JSON console output — is how the CI hardening pipeline attributes each diagnostic to a module so it can be routed to the right team; it is equally available for any other JSON-consuming tooling.