Repository navigation
4.1.6
4.1.6
Release Date: September 30, 2026
Behavior Changes
- The default HTTP client for the AWS SDK is switched from Poco back to the SDK's own client:
enable_poco_client_for_aws_sdknow defaults tofalse. Set it totrueto restore the previous behavior. #78375 - Online optimize table is now opt-in: the FE configuration
enable_online_optimize_tabledefaults tofalse, soALTER TABLE ... DISTRIBUTED BY ...again blocks writes unless the config is turned on. #78206 - jemalloc's dedicated oversize arena is enabled by default, so large allocations no longer land in the per-CPU arena of the calling thread. This improves reuse of large buffers and reduces fragmentation, and changes how BE and CN memory is distributed across arenas. #78396
- Shared-data tablet metadata and transaction log files are now written with an Adler-32 checksum by default (
lake_enable_protobuf_file_checksum), so corruption is detected on read. Readers already verified the checksum whenever a file carried one, so no downgrade step is needed. #75334 - A shared-data primary-key load that mixes
UPSERTandDELETErows for the same key now preserves their in-transaction order by default (lake_enable_pk_preserve_txn_delete_order). #76211 - Multi-table transactions now participate in shared-data batch publish instead of publishing one transaction at a time, which removes the serialization that CDC micro-batches fanning out to many tables used to hit. #77029
- A shared-data partition now advances straight to the final version of a batch publish instead of through each intermediate version, so a query can no longer request an intermediate version that has no tablet metadata object, which surfaced as
The specified key does not exist. #79175 - A shared-data publish that keeps failing now backs off and throttles its retry logging instead of emitting the
previous publish version task has not finishedmessage on every attempt, which could dominate the FE leader's CPU and log volume during an incident. #79299 - Del-file tombstone rows now count toward
cloud_native_pk_index_rebuild_rows_threshold, so a delete-heavy shared-data workload triggers the primary-key index early flush it was supposed to. #76222 - A shared-data column-upsert publish that supersedes its own segments now merges the delete vector, which previously could leave two live rows for one primary key. The damage only surfaced much later, when a CN restart rebuilt the persistent index and reported
insert found duplicate key. #78797 - The shared-data primary-key index compactor no longer stops silently while the flush side keeps producing sstables, which left a tablet whose persistent index grew without bound. #78812
- HDFS files are no longer
hsynced before they are closed. Thehsyncwas a workaround for a crash that a separate change had already fixed, and it forced anfsync()on every DataNode replica on each close. #78864 - A Parquet
null_countthat under-reports NULLs is no longer taken at face value during decoding and pruning. Files written by older parquet-mr versions previously returned corrupted values or dropped rows. #78329 - List partition pruning of
!=,NOT IN, andIS NOT NULLno longer discards a multi-value partition just because its value list also containsNULL. Queries on such a table, including joins that deriveIS NOT NULLon the join key, return the non-null rows that were previously lost. #78946 - Batch DDL can now build date range partitions that start at year
0000, which is a legalDATEvalue. Such a statement previously failed withthe range of the partition is invalid. #78746 max_partitions_in_one_batchand the partition-number limit now count the partitions the request in hand is about to create. An oversized batch is rejected up front instead of being admitted and only failing the following batch. #79379TRUNCATE TABLE <external_catalog>.<db>.<table>now checks theDELETEprivilege against the catalog named in the statement instead of the session's current catalog. A user who was previously allowed through may now be denied, and vice versa. #79047- Streaming aggregation tuning is now driven by the group-by cardinality instead of the rows left after
HAVING, so a query whoseHAVINGclause filters most groups away no longer loses its local pre-aggregation. #79064 - Audit log rows now carry
scanBytes,scanRows,returnRows,cpuCostNs, andmemCostBytesfor DML that targets an external Iceberg or Hive table or theFILES()table function, and for asynchronous materialized-view refreshes. These fields previously reported0. #74072 #74954 - The query profile and
EXPLAIN ANALYZEnow report the plan a retried query actually ran, rather than the plan from the first attempt. #79225 - A Broker Load no longer writes its submit-time snapshot of
enable_tablet_pre_splitback onto the submitting client's live session variable. #79177 ALTER MATERIALIZED VIEW ... ACTIVEworks again for non-aggregate incremental materialized views; the storage-filled__ROW_ID__column is kept out of the materialized-view DDL column list. #77017- The
Operationcolumn ofSHOW ALTER TABLE OPTIMIZEnow shows a readable description of the optimize operation instead of an internal object address such ascom.starrocks.sql.ast.OptimizeClause@b5dc069. #75948 - A column that is missing from the tablet schema no longer aborts the BE during predicate push-down; the predicate is simply not pushed down. #79234
- When
OlapTableSinkinitialization fails, the partially initialized sink is no longer taken through the full close path, which could dereference state that was never created and abort the BE. The original initialization error is returned instead. #79370 - Short key index page geometry is now validated without 32-bit overflow, so a corrupted page footer is rejected instead of wrapping and causing a heap out-of-bounds write. #79048
- An HTTPS request whose TLS handshake times out is no longer treated as connected and retried on the same socket. A stalled request now fails after approximately one timeout instead of
connect_timeoutplus two receive timeouts. #79369
Improvements
- LDAP and Active Directory groups can now be resolved from the user's
memberOfattribute, so a new directory group no longer requires a matching group-provider configuration on the cluster. #79254 - The audit log now records the query's error message, not just the coarse
ErrorCode, so a syntax error, an unknown table, and a privilege failure are distinguishable without correlating back tofe.log. #78798 - Added server-level spill metrics that aggregate spill activity across all spillable operators, broken down by local and remote storage backend. #71827
- Hudi metadata readers are now reused across the partitions of one scan instead of being rebuilt per partition, which shortens planning for tables with many partitions when the Hudi metadata table is enabled. #79367
- Tablet split points are now computed from a segment's existing indexes instead of a dedicated full sort key index page, so tables that never split no longer pay for writing and storing that page. #79050
/memznow accepts jemalloc's own statistics options, which makes the per-arena dirty and muzzy page counts and the extent size-class breakdown reachable from a running BE. #79090
Security
- [CVE-2026-55971] Bumped Apache Thrift to 0.24.0 to fix a heap-based buffer overflow in
THeaderTransport::untransform()in the C++ bindings. #76922 - [CVE-2026-42537, CVE-2026-59646] Bumped Apache Ranger to 2.9.0 to fix an RCE via JDBC URL injection, and Bouncy Castle to 1.85 to fix a DTLS reassembler buffer overrun. #79331
- [CVE-2026-71290] Bumped Apache HttpClient5 to 5.6.4. #79538
Bug Fixes
The following issues have been fixed:
SHOW PROFILELIST,ANALYZE PROFILE,get_query_profile(), and/api/profilereturned every cached profile, including other users' SQL text and plans, to any authenticated user. The new FE configurationauthorization_enable_query_profile_access_checkrestricts a cached profile to the user who ran the query and to holders ofSYSTEM OPERATE. #79375- The authorization check,
INSERTplanning, view expansion, the privilege check, andinspect_mv_refresh_infomade external-catalog round trips while holding an FE metadata lock, so a slow metastore stalled every DDL waiting on the same lock. Those calls now happen outside the lock. #79319 #79226 - A gtid and a partition version epoch could be generated on a non-leader FE, so two nodes could produce the same number at the same moment. #78799
FULL OUTER JOIN ... USING (c1, c2, ...)returned the wrong values: the firstUSINGcolumn was correct and every later one carried the previous column's value. AddingORDER BY <ordinal>to the same query failed with anIndexOutOfBoundsException. #79298- A
HAVINGpredicate was lost whenGROUPING SETS,ROLLUP, orCUBEwas rewritten into a union, so the query returned rows it was supposed to filter out. #79415 GROUP BY ROLLUP(a, b, a), andCUBEorGROUPING SETSnaming a column twice within one set, produced a grouping set that carried the same key twice. #78261- Removing the aggregation above an aggregate-key table dropped the query's
LIMITbefore it reached the storage layer, so the BE read the whole table. #79414 - Splitting an
ORjoin into a union lined up the branches inconsistently, because the union's output columns and the first branch were ordered by column id while the other branches followed the projection map's iteration order. #79473 - The skew-join rewrite replicated the preserved side of an outer join, so one input row could be returned several times and the result moved between runs. Its salt table also received the
generate_seriesarguments in the wrong order, so the series emitted nothing. #79168 #79268 SELECT DISTINCTaccepted anORDER BYon a column that theDISTINCTdrops, and the distinct push-down below a window left dropped columns in a projection. #77217 #77218- A window over an always-non-null aggregate such as
bitmap_union_count()lost its declared nullability, so aDISTINCTorGROUP BYover it failed witherror nullablel column. #79009 percentile_contmerge tracked exhaustion by value instead of by position, which could abort the BE. #77261count(DISTINCT percentile_hash(...)), and anyDISTINCTaggregate over aPERCENTILEvalue, crashed the BE; such a call is now rejected. #78795- The scalar agg-state combinators crashed on a null memory pool and raced on their nested function context. #76910
- A JSON subfield aggregate on an aggregate table failed with a raw
NullPointerException, because the synthetic subfield column has no aggregation type. #77952 - Streaming pre-aggregation could run out of memory under
enable_spill = true, because the limited-memory budget was latched once and never revised. #76702 - A spilling hash join cancelled while it was restoring build partitions crashed the BE, because the probe operator closed without waiting for the spill I/O tasks. #79085
- The local pass-through exchange kept appending chunks after the receiver was cancelled, and its channel could be used after free because the sink and the receiver did not share ownership. Sink readiness notifications also selected the sink observable but emitted a source event, so a driver blocked on
OUTPUT_FULLcould stay blocked. #76603 #77088 #76782 - The query cache could store an incomplete per-tablet result and serve it to later queries, and a fragment containing an ASOF join was cached even though the temporal condition never reached the digest. #77066 #77563
- An ASOF join whose temporal condition does not compare the two sides crashed the BE; such a condition is now rejected. #79049
- A nested-lambda slot with no parent tuple was treated as bound by the TopN node's tuple set when building runtime filters, and an order-by hint dereferenced a column-less slot pushed into the scan as a heavy expression. #78050 #78527
- Nested
array_mapandarray_sortlambdas failed to plan or evaluate withInput dependency cols check failedorExpr evaluate meet error: slot_id N not found, because common sub expressions hoisted by an inner lambda escaped the scope that defined them. #78645 #78769 #78915 array_sort's comparator validation shared one errorStatusacross drivers, which could double-free it. #78314array_contains(NULL, [1, 2])andarray_position(NULL, [1, 2])failed withclass com.starrocks.type.NullType cannot be cast to class com.starrocks.type.ArrayType. #76970- Analyzing
__iceberg_transform_truncateor__iceberg_transform_bucketmutated the shared builtin function object in place, stamping its wildcard decimal signature with the precision and scale of the first query analyzed. #76777 PARTITION BY RANGE(<partition-function>())with an empty argument list raised a rawIndexOutOfBoundsExceptioninstead of a parse error. #75080- A range predicate was mapped onto a partition expression regardless of whether the expression preserves order and in which direction, so range and list partition pruning could drop partitions that hold matching rows. A
NULLpartition key was also looked up at the column's type minimum rather than strictly below it. Retention conditions that cast aDATEorDATETIMEto text are accepted again. #78024 #79111 #79187 #79257 #79688 - The Iceberg predicate converter stripped a
CastOperatorunconditionally, soWHERE CAST(d AS BIGINT) = 10on aDECIMAL(5,2)column could prune a file holding10.50. #78351 - An incremental materialized view on an Iceberg base table was permanently inactivated by routine
rewrite_data_filescompaction, because the delta boundary advanced onto a skippedREPLACEsnapshot. #76950 - The column min/max statistics cache was not invalidated by partition or schema DDL, so a stale entry could be served indefinitely. #77441
- Hive-family catalogs failed outright when the metastore or AWS Glue denied permission to read column statistics; they now degrade to empty statistics. Glue column-statistics requests also carry
catalogId, so a cross-account deployment reads statistics from the configured catalog. #78455 #78461 - Elasticsearch external tables and Elasticsearch catalogs rejected clusters running version 8 or 9 with
Unsupported/Unknown ES Cluster version, and concurrent queries could overwrite each other's request URL parameters, which surfaced as unrelated analysis errors such asColumn 'id' cannot be resolved. #78267 #79391 - Predicates on a
DECIMALcolumn of a Paimon table were converted using the StarRocks type family's default precision and scale instead of the column's PaimonDecimalType, so the literal could not represent the value. #78760 - Azure Blob credential lookup failed when the endpoint was configured as a full URL, because the Hadoop configuration key embedded the scheme. ADLS2 storage volumes also dropped their Azure Workload Identity token-file property on serialization, so reloading the volume fell back to Managed Identity and failed with
Identity not found. #78241 #79444 - A JSON path with an array index such as
'[0].value.url'threw a C++ exception for every row whose array was shorter than the index, which turned a large scan into a lock convoy inside the stack unwinder. The index is now bounds-checked. #78569 timestampdiff(MONTH, ...),timestampdiff(YEAR, ...),months_diff, andyears_diffreturned-1instead of0when both arguments fell in the same month or year and the second was the earlier one. #79037- Constant folding of
CAST(<varbinary constant> AS VARCHAR)returned the Java identity hash code of the backing byte array, such as[B@233c25e5, instead of the value. #77718 DICTIONARY_GETrejected a non-NULL key as NULL when the input column's cachedhas_nullflag stayed conservatively true. #76881- A low-cardinality dictionary was kept on a nested-loop join's
ONcolumns even though the rewriter never decodes them, dictionary expressions were folded through derived dictionaries that carry their own codes, and a "rolling low-cardinality" column repeatedly invalidated the global dictionary and forced a full-table re-collection. #78229 #78633 #78486 - A
DECIMAL256literal was hashed from its string representation while the BE buckets rows from the raw 32-byte value, so point lookups on a table distributed by aDECIMAL256column were sent to the wrong bucket. #78495 - An OLAP scan named its sort key columns by column name rather than by column id, so a renamed column no longer matched the tablet schema. #77967
PruneComplexTypeUtildisabled complex-type subfield pruning for every column in the statement when it met a single expression it could not describe. The bail-out is now scoped to the expression that caused it, and dead subfield slots pulled out of the scan by predicate expression reuse are dropped. #79181 #77456AstToSQLBuilderprinted the columns of aSELECT * EXCLUDElist in double quotes, which the grammar accepts nowhere, so the regenerated SQL no longer parsed. #78052ALTER TABLE ... ADD COLUMNon an Aggregate table silently created a key column when neither an aggregate function nor theKEYkeyword was given, changing the grain the table aggregates on. Such a statement is now rejected as ambiguous. #78359- A column whose type has no BE key coder, such as
JSON, could be used as a sort key and crashed the BE; such a definition is now rejected inCREATE TABLEandALTER TABLEacross all distribution types. #76795 USING GIN("IMP_LIB" = "builtin")was accepted byCREATE TABLEand then broke everyINSERTwithCan not get inverted imp type, because the property key reached the BE with its original casing. #77818- A legacy
NGRAMBFindex persisted without itsgram_numproperty made the BE read past the UTF-8 offset vector and crash the CN while building a segment. #76989 - Null flags were indexed linearly rather than by ordinal when a pushed-down predicate read a sparse range, so every row after a gap took the null flag of a skipped row. The dictionary page decoder also failed to advance when a pushed-down filter rejected the whole dictionary, which aborted the BE. #78389 #79007
- A child expression error aborted the BE instead of being propagated. #77442
ThreadPoolswallowed task exceptions by default and counted the task as finished. #76863- Cancelling a load through
OlapTableSinkcrashed the BE or CN with a SIGSEGV when Jaeger tracing was enabled. #76869 AsyncFlushOutputStream::close()satisfied its promise while still holding the stream's own mutex, so the I/O thread woke futexes on freed memory after the waiter had destroyed the stream. #79182- A CN could crash with SIGSEGV during graceful shutdown when an in-flight load reached a StarOS-backed filesystem after
shutdown_staros_worker()had released the global worker. #79058 - Parallel compaction ran filesystem I/O on the brpc bthread, so the CN aborted with
Resource deadlock avoided. #76925 - Compaction aborted with SIGFPE when a vector-index rowset reported a negative
data_disk_size. #78959 - A corrupted local cache copy was re-read on every retry when a lake txn log read hit corruption, and primary-key index sstable block reads never verified the crc32c block trailer that the writer had always produced. #78733 #77479
- A partial-update rewrite that degenerated into a copy dropped the source's encryption metadata, leaving a segment that no reader could open and that compaction could not rewrite. #79053
- A shared-data schema change could record a rowset that references no data, after which every
MERGE_TABLETon the partition failed withtablet merge source has an empty ordinary rowset. #79167 - Range-colocate split bounds were compared as serialized protobuf bytes, which the FE and the BE do not encode identically. #76968
- A plain single-table query on a member of an unstable range-colocate group failed with
range colocate group ... is in an unaligned state. #76971 - Shards of a new physical partition of a hash-colocate shared-data table were created without colocation placement information and had to be migrated afterwards. #79223
- The FE did not tell the BE that a dropped tablet's table is range-distributed, which leaked files after a reshard. #76861
- Replaying a reshard job update did not refresh the resharding tablets, so after an FE leader change a partition's publish could 404 forever on a tablet metadata object that was never written. Replaying a reshard job could also write to the edit log when the table had been dropped, and reshard publish retries spun instead of being paced. #79426 #79485 #77691
- Shared-data partition versions were mutated in memory before the mutating operation was journaled, so a replayed version could move backwards. They are now derived from the journal and only ever advance. #79296
- A replication job divided by zero when the target tablet reported no replica. #79329
- The DataCache key hash was taken from a runtime dispatch table, so any change to that dispatch orphaned every cached block across an upgrade or rollback. It is now pinned to MurmurHash3. #79262
- The FE scan-range heap-safety check ran once per physical partition instead of once per scan node, which made it quadratic in the number of physical partitions. #76978
- Rowset metadata cache entries kept their initial charge after lazy-loaded indexes had increased segment memory usage, so the cache under-reported its footprint. #77893
Tablet::get_average_row_size()walked_rs_version_mapwithout holding_meta_lock, against the contract that map is declared with. #79250- The FE thrift accept loop stalled for minutes on worker-pool saturation, and workers kept serving connections that had been queued long after their callers were gone. #78838 #79173
- A non-leader FE whose journal applier was stuck kept serving stale metadata locally instead of forwarding, because the readiness verdict was only reached after a replay cycle returned. #79041
- The
getLoadsRPC returned every load record in a single message, so a busy cluster filled the leader log withFE RPC failure ... MaxMessageSize reachedand theloads_historyarchive rolled back and permanently lost rows. The RPC is now paginated by job id. #78898 - A task run that migrated between the pending queue, the running map, the in-memory history, and the archived history while
task_runswas being read could be reported twice. #79438 SHOW ALTER TABLE ROLLUPandSHOW ALTER MATERIALIZED VIEWacceptedWHERE,ORDER BY, andLIMITand then ignored them; onlySHOW ALTER TABLE COLUMNapplied them.FinishedTimeis also accepted in aSHOW ALTER TABLE ROLLUPpredicate. #79281 #79498- Loading the SQL blacklist rebuilt and sorted its immutable snapshot once per rule, which is quadratic in the number of rules and ran at every FE start and checkpoint. #78752
AsyncTaskQueuebusy-spun betweengetOutputs()andtryGetOutputs()after the consumer thread was interrupted, because the interrupt was swallowed without clearinghasMoreOutput. #79297- A runtime change of
sys_log_levelwas written to the configuration but never applied, even though the item is documented as mutable. #79200 has_enable_heap_profile()read the boolean jemalloc nodeprof.activeinto anint, so it always reported heap profiling as disabled. #78820System.print()on a script's foreign objects printedinstance of <Class>instead of the object's text, because thetoStringbindings were registered as methods rather than getters. #78877- Loading into an expression-partitioned table through the multi-table transaction stream load interface failed at commit whenever the BE had to create a partition, with
automatic create partition failed. error: txn ... not exist. #78790 - In combined txn log mode, a coordinator whose own end-of-stream arrived early could wait for the txn log collector indefinitely when the load was cancelled. #79389
- A completed merge-commit load could report less than full merge-window progress in
information_schema.loads. #78723 - The scan
SampleTimecounter reported a block count rather than elapsed time. #78732 - The LZ4 and ZSTD Arrow IPC codecs were missing from the FE classpath for the Arrow Flight SQL service. #76921
- Upgraded StarOS, starlet, and starcache to v4.1.4. #79429