5.23 Release notes
Upgrade guides
For general upgrade-script guidance, see the Cinchy upgrade utility.
v5.23 does not add any new services. However, several optional services were introduced in recent releases. If you are upgrading from a version earlier than these, you may want to add them as part of this upgrade:
- Cinchy MCP Server (new in v5.19): see MCP Deployment (Kubernetes) or MCP Deployment (IIS).
- Cinchy Email Notification Service (new in v5.20): see Notification Service Setup (Kubernetes) or Email Notification Service Deployment (IIS).
Cinchy v5.23 was released on September 30, 2026.
The v5.23 upgrade applies a model upgrade (model version 1.0.146):
- Can Design Queries on the
[Cinchy].[Users]table is renamed to Can Save Queries, and the new Can Write Queries column is added. See Query privileges split for what changes and what does not. - Five date columns that hold UTC timestamps move to a 24-hour display format. See Date columns display in 24-hour time. This part is metadata only and changes no data.
- Two seeded Observability queries are repaired so they run on SQL Server 2017 and 2019. See SQL Server 2017 and 2019 compatibility.
- Salesforce Change Data Capture is added to the Event Connector Type options of the
[Cinchy].[Listener Config]table. See the Connections release content.
The upgrade runs automatically on first start of the new version. Plan your upgrade window accordingly.
v5.23 upgrades the bundled Argo CD from v2.7.6 to v3.5.2. This is a required part of the Kubernetes upgrade, not an optional step, and it changes the command used to deploy Argo CD. See Argo CD upgraded to v3.5.2 below and the v5.23 Kubernetes upgrade guide.
IIS deployments are unaffected.
- Set a non-terminating rollout strategy on the Automation Runner. This applies to every Automation Runner upgrade, not only this one. See Upgrading the Automation Runner.
- Confirm
CinchyEnvironmentis set on the Automation Runner. It is injected by the standard deployment. If it is missing, the consumer falls back to the previous lock behavior and logs a warning at startup. - Close any executions already stuck at
Running. v5.23 prevents new executions from being orphaned, but it does not close rows orphaned by earlier versions. The Skip and Wait concurrency policies count rows inRunningstate, so an automation with a stuck row will not start until that row is closed. See An execution is stuck at Running.
On Kubernetes, a defect fixed in v5.23 could leave the nightly maintenance Job running forever, which silently suppressed every later run. Upgrading does not clear a Job that is already in this state, so check before you upgrade:
kubectl -n <namespace> get jobs -l app=maintenance-cli
kubectl -n <namespace> delete job <hung-job-name>
Your environment is affected if a maintenance-cli Job has an active pod, or if [Cinchy].[Execution Log] has a row with [Command] = 'Maintenance' stuck at [State] = 'Running'. See Maintenance has stopped running.
Infrastructure
Argo CD upgraded to v3.5.2
Kubernetes deployments move from Argo CD v2.7.6 to v3.5.2.
Why this is required
Argo CD v2.7.6 embeds a Kubernetes OpenAPI schema that predates .status.terminatingReplicas, a field added to Deployment and ReplicaSet status in Kubernetes 1.33. On clusters running 1.33 or later the API server populates that field unconditionally, so Argo CD's structured-merge diff cannot build a typed value from the live resource and the comparison aborts with:
ComparisonError: error calculating structured merge diff: error building typed
value from live resource: .status.terminatingReplicas: field not declared in schema
Any Application that combines ServerSideApply=true with a Deployment in its resource tree is left stuck at Sync Status Unknown. Health reporting still works and workloads keep running, which makes the problem easy to miss, but drift detection, selfHeal, and prune are all silently inoperative for those Applications. In a standard Cinchy deployment this affects kube-prometheus-stack, keda, and logging-operator.
Upgrading Argo CD is the only fix: the schema is compiled into the Argo CD binary and cannot be patched through configuration.
Server-side apply is now required
Argo CD v3.x ships substantially larger CRDs:
| CRD | Approximate size |
|---|---|
applications.argoproj.io | 412 KB |
applicationsets.argoproj.io | 1.4 MB |
Both exceed the 262144-byte ceiling on the kubectl.kubernetes.io/last-applied-configuration annotation that client-side apply writes. A plain kubectl apply -k argocd therefore fails with:
The CustomResourceDefinition "applicationsets.argoproj.io" is invalid:
metadata.annotations: Too long: may not be more than 262144 bytes
deploy_argocd.sh is now generated with the required flags:
kubectl apply -k argocd --server-side --force-conflicts
This applies to fresh installs as well as upgrades, because kubectl records that annotation on create as well as on update. If you maintain a customized copy of deploy_argocd.sh, add --server-side --force-conflicts to it.
Other Argo CD changes
- The Argo CD
kustomization.yamlmigrates from the deprecatedpatchesJson6902field topatches(kustomize v5). - Argo CD v3.x adds seven
NetworkPolicyresources that did not exist in v2.7.6. Seeing these created during the upgrade is expected. - The v2.7.6 manifest is retained in the
cinchy.argocdrepository so a rollback remains possible.
Kubernetes version support
- Azure Kubernetes Service (AKS): default moves to 1.36.3 (from 1.34.5).
- Amazon Elastic Kubernetes Service (EKS): 1.34.
The AKS default is set in cinchy.devops.automations/azure.json (kubernetes_version and orchestrator_version); the EKS version is set in aws.json (cluster_version). Kubernetes upgrades must still be performed one minor version at a time, see Upgrade AWS EKS and Azure AKS.
New capabilities
Query privileges split into Can Save Queries and Can Write Queries
The single Can Design Queries privilege governed both composing a query and saving one, so the only two settings were "can save queries anywhere" and "cannot run a query from the UI at all". v5.23 splits it in two, adding the position in between: business users who compose, run, and export queries, but persist nothing.
On the [Cinchy].[Users] table:
| Privilege | Governs |
|---|---|
| Can Save Queries (renamed from Can Design Queries) | Persisting a saved query: save, delete, and query permissions, including via CREATE VIEW, ALTER VIEW, and DROP VIEW. |
| Can Write Queries (new) | Opening the query designer and running ad-hoc CQL. |
Saving implies writing, so a user who can save is never shut out of the editor, and Cinchy Administrators bypass both.
A user with Can Write Queries but not Can Save Queries sees the query designer as a query runner: no Save button, no Info or Permissions tab, and no Delete. They can still run ad-hoc CQL, including DML, and export the results.
Nothing changes for existing users on upgrade. The upgrade backfills Can Write Queries from each user's previous Can Design Queries value, so a user who could not open the query editor before still cannot.
The rename is breaking for anything that references the column by name. Data syncs, saved queries, models, scripts, and integrations that select or write [Cinchy].[Users].[Can Design Queries] must be updated to [Can Save Queries]. The column's guid is unchanged, so references by guid (for example in models) keep working.
Alongside the split, the privilege is now enforced at every route into a saved query, several of which were previously open:
- Editing an existing saved query (including through
ALTER VIEW) checked the privilege only when creating, and deleting a saved query (including throughDROP VIEW) had no check at all. - Deleting a saved query now also honours the per-query design entitlement, so a privilege holder can no longer drop another team's query.
- CQL written directly at
[Cinchy].[Saved Queries]is now refused for users without the privilege. Writes to every other table are untouched, as are the platform's own writes, upgrades, and CinchyDXD installs.
Enhancements
Automations
- Higher automation throughput where environments share Redis. The automation consumer's distributed lock is now scoped by environment rather than by the Cinchy service URL. The URL is an internal service name and is identical in every environment, so environments sharing a Redis instance contended for a single lock and only one of them could consume automations at a time. On a shared non-production cluster, the time from a scheduled trigger to the automation starting dropped from over 11 minutes to under a minute.
- New
Kafka:ConsumeTimeoutMssetting (default5000) bounds the Kafka poll that runs inside that lock. It previously reusedKafka:SessionTimeoutMs, which is60000in every shipped configuration, so a runner that found an empty queue held the lock for a full minute. - Connections service name overrides restored.
webServiceEndpoint(defaultweb-service,cinchy-web-svc) andconnectionsServiceEndpoint(defaultconnections-service) are supported again on the Automation Runner, for deployments whose services are named differently from the defaults. These existed in v5.15.1 and v5.15.2 and were removed in v5.15.3. With neither set, resolution is unchanged. The runner logs the address it resolved at startup.
Maintenance
- Scheduled maintenance now refreshes the Observability dashboard. Baseline metrics and health snapshots are recalculated, snapshots past their retention window are pruned, and the event listener counters are reset. This work previously had no scheduled caller anywhere in the product, which is why health scores stayed empty until someone pressed the button in the dashboard. It runs first in the nightly job so a tight maintenance window cannot starve it, and a failure there does not abort the rest of the run. Skip it with
--no-observability; set the snapshot retention window with--observability-retention-days(default90, range 1 to 365). - A defined set of
[Cinchy]system tables is now eligible for erasure and compression, where maintenance previously refused all of them. The Design Table screen shows the Erasure and Compression tabs for exactly these tables and no others. Nothing changes until you set a retention policy. See System tables for the list and what to know before setting a policy. - A run that exhausts its time window now reports what it got through. The Execution Output gives tables completed of total, the table that was in flight, batch throughput, and an estimate of the time remaining. It also says so explicitly when no table has a retention policy configured at all.
- Batches Executed is now populated. The counter was never incremented, so it had always displayed
0.
Connections
-
New ODBC Table destination. Connections can now write to any database that has an ODBC driver, using the new ODBC Table destination. It is intended for databases without a dedicated destination, such as Db2 for i (AS/400), Informix and Teradata. It supports Full File and Delta syncs, batch and real-time, with insert, update, and the Delete and Expire dropped-record behaviours. Target column names must match the database catalog exactly, including case; Load Metadata in Column Mappings fills them in. The ODBC driver for the target database must be installed where Connections runs; the Connections images do not include one. See the ODBC table destination for driver setup and connection string examples.
-
Salesforce connectors support the OAuth 2.0 Client Credentials flow. The Salesforce source, destination, Push Topic listener and Platform Event listener gain a Grant Type setting with two options: Username-Password, the existing behaviour and still the default, and Client Credentials, which authenticates through a Salesforce External Client App with no Salesforce user login. Existing syncs and listeners are unchanged on upgrade. See the Salesforce object (Bulk API) source and the Salesforce destination.
Salesforce is retiring the Username-Password flowSalesforce no longer allows new Connected Apps to be created, and its replacement, External Client Apps, does not offer the Username-Password flow. Salesforce has scheduled the flow itself for retirement on February 20, 2027. Use Client Credentials for new Salesforce integrations, and plan to move existing ones before that date.
Client Credentials is only served from your org's My Domain host, so when you switch an existing configuration also change its Auth URL to
https://<mydomain>.my.salesforce.com/services/oauth2/token. -
Clearer Salesforce authentication errors. A failed login now reports the error Salesforce returned, rather than a generic prompt to verify the credentials.
-
Salesforce Change Data Capture listener. A new Salesforce Change Data Capture event connector type subscribes to Salesforce change events for one object (create, update, delete and undelete) and applies them to the target table in real time. Salesforce labels PushTopic events a legacy product and no longer enhances them; Change Data Capture is its recommended replacement, retains events for 72 hours instead of 24, and needs nothing created in the Salesforce org. Cinchy reads each changed record back from Salesforce before it syncs it, so mapped columns are never overwritten with blanks and formula fields can be mapped. The sync key of the data sync must be the destination column mapped from
Id, and the object must be enabled for Change Data Capture in Salesforce Setup; the listener checks both when it starts and reports what to fix. See Salesforce Change Data Capture for configuration, behaviour on gap and overflow events, and the steps to move an existing Push Topic sync. -
Salesforce API version 67.0. The Salesforce source and destination (Bulk API 2.0) and all three Salesforce listeners now call Salesforce API version 67.0 (Summer '26) instead of 47.0. No configuration change is needed. The
ApiVersioninside an existing Push Topic's Topic JSON is that topic's own setting and is unchanged.
Cinchy MCP Server
- Entitlement-aware tool descriptions. When entitlements filter rows or mask columns, AI clients previously treated the withheld data as an anomaly to investigate, producing speculative narration about missing data; a denied write invited the model to look for workarounds. The tool descriptions now tell the client that withheld rows and columns are expected governance to note briefly and move past (pointing at
check_user_permissions), and that a write denial is an access boundary, not an obstacle to route around. This is a description-only change; no tool behavior changes.
Identity Provider (IdP)
- Token signing health check. The IdP's
/healthcheckendpoint now verifies that token signing is working and returns aToken SigningRed entry with a 503 if it is not, so a node that cannot issue tokens is taken out of rotation by any load balancer already probing the endpoint. No reconfiguration is required. - Startup verification. The IdP now verifies token signing before it accepts traffic and will not start if the signing certificate is unusable, rather than starting and failing every token request.
Observability dashboard
- Faster dashboard loading for large environments. The Observability dashboard's queries have been optimized, improving load times on environments with a large execution history.
Fixes
Automations
v5.23 is a substantial reliability pass on Cinchy Automations.
Any automation using a pre-seeded Quartz schedule, day of week 7, or a list containing spaces was previously accepted but never fired. After upgrading, these run on schedule. Review your enabled automations before upgrading if that could be disruptive.
An automation with a malformed schedule now logs an error on each scheduler run instead of failing silently, which can surface misconfiguration that was previously invisible.
Scheduling
Cron expressions are now evaluated by the Cinchy Scheduler itself rather than by the container's cron daemon. See Schedules and cron expressions for the supported syntax.
- One bad expression no longer stops every automation. An expression the cron daemon could not parse was rejected along with the whole schedule file, which silently stopped scheduling for every automation in the environment. A malformed expression now disables only its own automation and logs the reason.
- Pre-seeded Quartz schedules now fire. First Monday of Every Month at 8:00 AM and Every 15th and Last Day of the Month at 6:00 AM could be selected in
[Cinchy].[Schedules]but never ran. - Day of week
7is accepted as Sunday, as the field description states. - Day of month and day of week now combine with OR, matching standard cron:
0 0 1 * MONfires on the 1st of the month and on every Monday. - Spaces in lists are tolerated.
MON, TUEnow matches. - Malformed field values are reported rather than silently never matching, including out of range values, reversed ranges such as
5-1, and zero steps such as*/0. - Overlapping scheduler runs can no longer publish the same automation twice.
- An unreachable Kafka broker no longer stalls scheduling. Publishing is now bounded per automation and per scheduler run, so a broker outage delays the affected automations instead of every automation after them.
- A failed query no longer looks like "all automations deleted". A transient failure retrieving active automations was treated as an empty result and removed every schedule.
- Change detection is correct on sub-hour UTC offsets. Servers on India (+5:30), Nepal (+5:45), Iran (+3:30) and Central Australia (+9:30) were adjusted wrong by 30 to 45 minutes.
Execution history
- A verbose step no longer leaves an execution stuck at
Running. When a step produced a large log, the write that closes the execution row exceeded the column limit and was rejected without being detected, so the row stayed atRunningindefinitely even though the automation had done its work. Messages are now truncated to the column width, keeping the end of the log where the status and any error appear, and the closing write is verified and retried. - Step rows close too. An error between a step starting and finishing previously left the step at
Runningwhile the automation itself closed correctly. - Execution history is no longer lost on comma-decimal hosts. Numeric values were formatted using the host's locale, so on a host using a comma as the decimal separator the history write failed and no record was kept.
- The
(UTC)columns now hold UTC. Values were converted to UTC and then coerced back to the host's local time before being written.
Automation steps
- A timed-out Data Sync step now cancels its sync. The sync's execution id was written and read from different locations, so the cancel was skipped and the Connections job ran to completion long after the automation had given up. Max Execution Time on a Data Sync step now takes effect.
- A sync that ends in a non-success state now fails the automation. A cancelled or failed sync previously left the automation reporting
Succeeded. - A sync that never starts is now reported as failed. A Connections request could return success with no execution id, meaning the sync never began, and this was treated as a successful step.
- A step with no Max Execution Time is no longer terminated immediately. An unset value was treated as a limit of zero, so the step was stopped roughly 100 ms in and reported
Automation Step Max Execution Time of exceededwith an empty duration. Such a step now runs bounded by the pod lifetime. - A Code Bundle step now receives the automation's connection configuration. Without it the bundle fell back to an empty configuration, did no work, and the step still reported
Succeeded. - A Code Bundle that exits without setting an exit code is no longer reported as failed.
- SLA breach detection works on pods with a timezone set. The elapsed time used for the check could go negative, which disabled the check.
Notifications
-
Automation notification emails now carry the execution id and resolve
{{trigger_type}}(SuccessorFailure) in a subject template, so a notification can be traced back to its run. -
Subject template, reply-to, from address, from display name, priority and branding configured in
[Cinchy].[Notification Config]are now applied to automation notifications whether or not the recipients came from that configuration.Behavior changeAn environment that set these overrides and also supplied recipients directly has been receiving service defaults, and will start receiving its configured values.
Date columns display in 24-hour time
Five columns that hold UTC timestamps were displayed in 12-hour format with no AM/PM indicator, so 14:05 appeared as 02:05:00:
[Automation Steps Execution History].[Trigger Time (UTC)][Observability Health Snapshots].[Snapshot Time][Observability Baseline Metrics].[Baseline Start Date],[Baseline End Date]and[Calculated At]
The model upgrade applies the 24-hour format to existing installations as well as new ones.
Maintenance
- Scheduled maintenance could stop running permanently, with nothing in any log to say so. An exception in the console writer left the process unable to exit. The Kubernetes Job stayed active, and because the CronJob uses
concurrencyPolicy: Forbid, every later schedule was skipped for as long as that Job existed. Environments in this state have never run scheduled maintenance. The fix prevents it recurring, but it cannot clear a Job that is already hung. See Maintenance has stopped running. - A failed run now exits non-zero. The process exited
0even when the run failed, so Kubernetes recorded a failed maintenance run as a success, which defeatedbackoffLimitand any alerting built on Job status. Expect failed Jobs to become visible that were previously silent. - A connection failure at startup now produces a log entry. The Cinchy client resolves the identity provider URL at startup, before the run's own error handling begins, so a DNS or TLS failure produced a bare stack trace with no Serilog record and no
[Cinchy].[Execution Log]row at all. - Elapsed time is now correct. Every run reported a duration near zero regardless of how long it took.
- Compression now runs inside the transaction it appeared to be in. The web controller's compress path called the erase routine without the connection and transaction.
- The CLI no longer loops on errors for a half-configured table. It treated compression as enabled when either version column was set, while the server requires both.
SQL Server 2017 and 2019 compatibility
The seeded Observability - Refresh Health Snapshots query used LEAST and GREATEST, which are SQL Server 2022 built-ins. On SQL Server 2017 or 2019 the query failed with 'LEAST' is not a recognized built-in function name. Both are now expressed as CASE arms.
Observability - Refresh Baseline Metrics also aggregated execution log rows whose Data Sync Configuration had since been deleted. It now requires the configuration to still exist.
Both queries previously shipped from two places, one path for fresh installs and one for upgrades, and the two copies had drifted, so fresh and upgraded environments were running different SQL. They now share one definition.
The model upgrade repairs the stored queries on existing environments, but only where the stored text still matches a body the platform previously seeded. If you have edited either query yourself it is left untouched and a warning is logged, and you will need to apply the change by hand.
Query Execution Plan viewer
Fixes to the Query Execution Plan viewer introduced in v5.21.
- Estimated plans now work for queries that take parameters. On SQL Server, requesting an estimated plan for a parameterised query failed with
Failed to retrieve execution plan from database. The query editor now passes the values entered in the parameter prompt, and a parameter left blank binds toNULL. Actual plans are unchanged. - Multi-statement queries that build temp tables now return a plan. A batch that uses
CREATE TABLE #tfollowed byINSERT INTO #t ... SELECTreturns a full estimated plan, with every insert step present. A batch that usesSELECT ... INTO #treports that SQL Server cannot estimate a plan for that form and points to theCREATE TABLEalternative. - Fresh installs showed GUIDs in place of the viewer's labels. A new environment never runs the upgrade steps that seeded the viewer's text. The same literals are now seeded on install.
Connections
-
The Expire dropped-record behaviour now works on the Db2 Table, Oracle Table and Snowflake Table destinations. A Full File sync with Dropped Record Behaviour set to Expire failed on Db2 and Oracle, and on Snowflake for batches of ten records or fewer, because the Expire statement was built with SQL Server's parameter syntax regardless of the destination.
-
Delete and Expire now use the configured ID Data Type when matching records in the destination. Previously the ids were always compared as text.
Behavior changeDestinations with an ID Data Type of Text, the default, are unchanged. Those set to Number now compare numerically.
-
A blank ID Column is rejected when the sync is saved. A Full File sync into an ADO.NET destination with Dropped Record Behaviour set to Delete or Expire and an empty ID Column was accepted and then failed every dropped-record batch at run time. In hand-written XML, a missing
reconcileDataattribute is now treated as Full File for this check, which is how the destination already behaves. -
Long-running Salesforce syncs no longer fail when the access token expires. A Salesforce batch sync that outlived its access token stopped with
INVALID_SESSION_ID. The connector now signs in again and continues.
Platform
-
INSERT INTO ... SELECTignoredWHERE,GROUP BYandHAVING, inserting every row of the source. This affected everyINSERT INTO ... SELECT, Cinchy-table targets as well as#temptables.Behavior changeFilters on an
INSERT INTO ... SELECTare now applied. Any query that relied on the previous unfiltered result will insert fewer rows. -
Create menu options were neither dimmed nor blocked. The launcher's Create menu dimming and click guards pointed at elements that do not exist, so Spatial Table in particular offered an action the server then refused. The menu now disables the options the user has no access to. (Server-side enforcement was already correct; this only stops offering the action.)
-
Saved query page 500 on a stale session. Opening a saved query when the session no longer resolves to a user returned a server error instead of degrading to the Execute tab.
Security
- IdP token signing hardening. Certificate and private-key handling in the Identity Provider has been hardened against a condition that could leave a node unable to sign tokens.
- Saved query persistence closed at the CQL layer. Writes aimed directly at
[Cinchy].[Saved Queries]now respect the Can Save Queries privilege, closing a route that previously bypassed the application's own checks. See Query privileges split. POST /Query/Savewas routable viaGET. The action is nowPOST-only.