Skip to content

Envelope Validation

Strata includes built-in envelope validation that checks the structure of every message before it is processed. This catches malformed requests, bad field types, and missing required fields at the transport layer -- before your operation handlers or middleware ever see the message.

Validation is enabled by default and has near-zero performance overhead.

Why Validate Envelopes

  • Runtime type safety. TypeScript types disappear at runtime. A service can receive a payload that is null or an array instead of the expected object. Envelope validation catches these at the boundary.
  • Better error messages. Invalid requests get a clear failed response explaining what's wrong, instead of an opaque crash somewhere in your handler.
  • Cross-implementation compatibility. If you have Strata services written in different languages or different versions, validation ensures they all conform to the same wire format.
  • Bug prevention. Catches structural errors during development and testing before they reach production.

Performance

Validation uses hand-rolled checks with simple JavaScript primitives (typeof, equality comparisons, Array.isArray()). No schema libraries, no runtime compilation.

Benchmark results (Apple M1 Max, Node.js v20.x, 100,000 iterations):

MethodTime per OperationOverhead
No validation1.09 us/opbaseline
Hand-rolled validation1.09 us/op0%
Zod schema validation43.17 us/op3,860%

The validation checks are so fast they're lost in the noise of JSON.parse() itself. At 10,000 requests per second, hand-rolled validation adds less than 0.1% additional CPU time compared to no validation at all.

Scenario (10K req/sec)CPU Time per Second% of CPU Core
No validation~11ms~1.1%
Hand-rolled validation~11ms~1.1%
Zod library~455ms~45.5%

Configuration

Validation is configured per-backend using the validateEnvelopes option.

Enabled (Default)

typescript
const service = new StrataService({
    service: { serviceGroup: 'MyService' },
    backend: {
        type: 'redis-streams',
        redis: { host: 'localhost', port: 6379 },
        // validateEnvelopes defaults to true -- no need to set it
    },
});

Disabled

typescript
const service = new StrataService({
    service: { serviceGroup: 'TrustedService' },
    backend: {
        type: 'redis-streams',
        redis: { host: 'localhost', port: 6379 },
        validateEnvelopes: false,
    },
});

WARNING

Disabling validation removes a safety net for negligible performance gain. Only do this if you fully control every service on the bus and have verified envelope correctness through other means.

What Gets Validated

Validation checks the structure and types of message envelopes. It does not inspect payload contents -- that's your handler's responsibility.

Request Envelopes

FieldTypeRequiredNotes
idstringyesMust be non-empty
messageType'request'yesLiteral value
contextstringyesMust be non-empty
operationstringyesMust be non-empty
timestampstringyesMust be non-empty
payloadobjectyesNot null, not an array
metadataobjectyesNot null, not an array
responseQueuestringno
timeoutnumberno
authstringno
clientstringno
priorRequeststringno
requestChainstring[]noMust be an array if present

Response Envelopes

FieldTypeRequiredNotes
idstringyesMust be non-empty
messageType'response'yesLiteral value
contextstringyesMust be non-empty
operationstringyesMust be non-empty
timestampstringyesMust be non-empty
payloadobjectyesNot null, not an array
status'succeeded' | 'failed' | 'pending'yes
messagesResponseMessage[]yesEach message is validated
servicestringyes

Each ResponseMessage in the messages array must have:

FieldTypeRequiredNotes
severity'error' | 'warning' | 'info' | 'debug'yes
messagestringyes
codestringno
typestringno
stackstringno
detailsobjectnoNot an array if present

Post Envelopes

FieldTypeRequiredNotes
idstringyesMust be non-empty
messageType'post'yesLiteral value
contextstringyesMust be non-empty
operationstringyesMust be non-empty
timestampstringyesMust be non-empty
payloadobjectyesNot null, not an array
metadataobjectyesNot null, not an array
authstringno
clientstringno
priorRequeststringno
requestChainstring[]noMust be an array if present

Service Commands

All commands require id (non-empty string) and command (string). Additional fields vary by command:

CommandAdditional Required Fields
inforesponseChannel (string)
concurrencypayload.concurrency (number)
shutdownNone -- payload is optional (graceful: boolean, exitCode: number)
toobusypayload (object, all fields optional: maxLag, interval, smoothingFactorOnRise, smoothingFactorOnFall -- all numbers)

Command Responses

FieldTypeRequiredNotes
idstringyesMust be non-empty
payloadobjectnoNot an array if present

What Is NOT Validated

Payload contents are not inspected. Validation only checks that payload is a non-null, non-array object. Your handlers and middleware are responsible for validating the actual contents:

typescript
ctx.registerOperation('update', async (request) =>
{
    // Envelope validation guarantees payload is an object.
    // You must validate its contents:
    if(!request.payload.userId || typeof request.payload.userId !== 'string')
    {
        throw new Error('userId is required and must be a string');
    }

    // Process the request...
});

Error Handling

What happens when validation fails depends on the message type:

Invalid Requests (Service Side)

  1. The backend validates the envelope structure.
  2. If invalid: extract minimal fields (id, responseQueue, context, operation) if possible.
  3. Send a failed response with message: "Envelope validation failed: The request envelope structure is invalid."
  4. If responseQueue can't be extracted, log a critical error and drop the message.
  5. The incomingRequest event is not emitted -- your handlers never see the request.

Invalid Responses (Client Side)

  1. The backend validates the envelope structure.
  2. If invalid: log a warning and drop the message.
  3. The incomingResponse event is not emitted.

Invalid Posts

  1. The backend validates the envelope structure.
  2. If invalid: log a warning and drop the message.

Invalid Commands

  1. The backend validates the command structure.
  2. If invalid: log a warning and drop the message.

When to Disable Validation

Almost never. The performance cost is effectively zero, and the safety benefits are real. That said, there are narrow cases where disabling makes sense:

Disable when:

  • All services are written and controlled by your team
  • All services use the same Strata version
  • Services communicate on a fully trusted network
  • You have verified envelope correctness through other means (comprehensive integration tests)

Keep enabled when:

  • Services communicate across team or organization boundaries
  • Multiple Strata implementations are in use (different languages, different versions)
  • Third-party services connect to your bus
  • Development or staging environments (where bugs are most common)

Troubleshooting

"Envelope validation failed" Errors

Your client is receiving a failed response with a validation error message.

Check:

  • All required fields are present (see tables above)
  • payload is an object ({}) -- not null, not an array, not a primitive
  • metadata is an object if present
  • messageType matches the expected value ('request', 'response', or 'post')
  • String fields are non-empty
  • For responses: status is one of 'succeeded', 'failed', 'pending'
  • For responses: messages is an array with valid severity values

Validation Passes But Handler Fails

This means the envelope structure is correct, but the payload contents are wrong. Envelope validation only checks structure -- not business logic. Validate payload contents in your handlers or use the Payload Validation Middleware.

Best Practices

  1. Leave validation enabled. The 0-2% overhead is negligible. The safety is not.
  2. Validate payload contents yourself. Envelope validation checks structure, not business data. Use middleware or handler-level checks for payload validation.
  3. Handle validation errors in clients. Check for failed responses with validation error messages and handle them appropriately.
  4. Monitor validation failures. Log and alert on validation errors -- they indicate a bug in a service or client.
  5. Test with validation on. Always run tests with validation enabled to catch structural issues early.

Next Steps

  • Backends -- backend-specific configuration, including validateEnvelopes.
  • Configuration -- full configuration reference.
  • The Protocol -- the envelope format that validation enforces.