<@U0A71G31CDV> We continue to have regular proble...
# questions-and-troubleshooting
g
@Rocky We continue to have regular problems with stuck transactions taking 2 days to 'publish' but never finish. And queries that took 20 minutes are now taking 4 hours to insert 19 million records. At your suggestion we changed our table from Primary Keys to Duplicate Keys. We also upgraded to 4.09. We are running 3 FE and 5 CN on a shared MS Blob storage. raw_import_timestamp is a datetime field of when the data was imported into the RAW table. event_time is a datetime field of when the event being tracked happened. car_row_id is a 64 byte string unique identifier. We ingest about 60 mission records per day. Here are our RAW ingestion tables configuration:
Copy code
ENGINE=OLAP
DUPLICATE KEY(raw_import_timestamp)
PARTITION BY date_trunc('day', raw_import_timestamp)
PROPERTIES (
    "compression" = "LZ4",
    "datacache.enable" = "true",
    "datacache.partition_duration" = "1 DAY",
    "fast_schema_evolution" = "true"
);
here is the structure of our second level 'C' tables.
Copy code
PRIMARY KEY(event_time, region, car_row_id)
PARTITION BY date_trunc('day', event_time)
ORDER BY (event_time)
PROPERTIES (
    "compression" = "LZ4",
    "datacache.enable" = "true",
    "enable_persistent_index" = "true",
    "persistent_index_type" = "CLOUD_NATIVE"
);
The issue is when we run this:
Copy code
SHOW PROC '/transactions/events/running';
All of the results have a 'CommitTime', but we see many records without a 'PublishTime' from 2 days ago and no , and some from 2 days ago that have a 'PublishTime' but still no 'FinishTime' What can be the cause and how can we fix it?
😮 1
r
The behavior you're describing—transactions stuck in
COMMITTED
(waiting for Publish) or
PUBLISHED
(waiting for Finish) for multiple days—typically indicates a bottleneck in the Metadata/Transaction management or Object Storage (Azure Blob) latency. Since you are running in shared-data mode (CN + MS Blob), here are the most likely causes and the steps to fix them: 1. FE Thread Pool Exhaustion (Most Likely for "Stuck" Txns) If transactions have a
CommitTime
but no
PublishTime
, the FE may have failed to submit the "Publish Version" task to the CNs, or the internal task queue is full. * Check FE Logs: Search
fe.warn.log
or
fe.log
for strings like
rejected from agent-task-pool
. * Cause: StarRocks uses a thread pool (
agent-task-pool
) to send tasks to CNs. If you have many tablets or very high-frequency small loads, this pool (default 4096) can become exhausted. * Fix: Increase the thread pool size in `fe.conf`:
Copy code
properties
    # Requires FE restart
    agent_task_resubmit_wait_time_ms = 1000
    # Monitor if this is full
Also, check if
lake_publish_version_max_threads
(default 512) is sufficient for your load concurrency. 2. Version Continuity Gap In shared-data mode, StarRocks requires strictly sequential versions to publish. If transaction
N
is stuck or fails, transactions
N+1
,
N+2
, etc., will stay in
COMMITTED
state and never become
VISIBLE
. * Diagnosis: Run
SHOW PARTITIONS FROM <table_name>
and compare
VisibleVersion
with
NextVersion
. If there is a gap (e.g., Visible=100, Next=105), transactions 101-104 are likely stuck. * Cause: Often caused by a failed schema change or a CN crash during a critical publish phase. * Fix: Check
fe.log
for
partition.getVisibleVersion() + 1 != version
. You may need to manually abort the oldest stuck transaction if it hasn't timed out, or in extreme cases, contact support if a metadata repair is needed. 3. Azure Blob Storage Latency & Small Files The drop from 20 minutes to 4 hours suggests I/O amplification or Metadata overhead on Azure Blob. * The PK Table Issue: Your second-level 'C' table uses a
64-byte
string (
car_row_id
) in the Primary Key. Large keys increase the size of the Cloud Native Persistent Index. Every insert requires reading/writing these index files to Azure Blob. * The Bucketing Issue: If your
PARTITION BY
is very granular (e.g.,
date_trunc('day')
) and you have many buckets, you create thousands of small metadata files on Azure Blob per transaction. * Fixes: * Batch your inserts: Ensure you aren't doing many small
INSERT
statements. 19M records should ideally be one or a few large transactions. * Optimize Bucketing: Ensure each tablet (bucket) is ~1GB to 10GB. If tablets are too small, metadata operations on Azure Blob will crawl. * Enable File Bundling (v4.0+): Since you are on 4.09, ensure file bundling is enabled to reduce the number of small files written to Azure:
Copy code
sql
        ADMIN SET FRONTEND CONFIG ("enable_paimon_file_bundle" = "true"); -- if applicable
        -- and check table properties for "file_bundle"
4. Compaction Backlog If background compaction tasks are stuck, they can hold locks or consume the
lake_publish_version_max_threads
pool. * Check Compactions:
Copy code
sql
    SHOW PROC '/compactions';
    -- Check if many tasks have StartTime but no FinishTime
* Fix: If you see thousands of stuck compactions, you can temporarily throttle them to let ingestion catch up:
Copy code
sql
    ADMIN SET FRONTEND CONFIG ("lake_compaction_max_tasks" = "100"); -- lower this if it's too high
Recommended Diagnostic SQLs Run these to pinpoint where the delay is: 1. Check for rejected tasks:
grep "rejected" fe.log
2. Check partition version lag: ```sql SELECT DB_NAME, TABLE_NAME, PARTITION_NAME, VISIBLE_VERSION, NEXT_VERSION FROM information_schema.partitions_meta
WHERE NEXT_VERSION - VISIBLE_VERSION > 1; ``` 3. Check CN health: Ensure all 5 CNs are
Alive
in
SHOW COMPUTE NODES;
. If a CN is flapping, the FE will keep trying to send publish tasks to it and timeout. Note on v4.09: As this is a very recent version, ensure that
lake_enable_batch_publish_version
is set to
true
(it should be by default) to minimize RPC calls to Azure Blob. Referencesadministration/management/FE_configuration.mdadministration/management/BE_configuration.md
g
@Rocky what grafana dashboards and specific metrics can we look at to help diagnose why this happens and how to prevent in the future?
r
To diagnose your performance degradation and stuck transactions, you should focus on the Shared-data and Starlet Grafana dashboards. These provide a window into the interaction between your FE/CN nodes and Azure Blob Storage. 1. Recommended Dashboards If you haven't already, import these templates (available on the StarRocks Monitoring Page): * Shared-data Dashboard (General): Tracks high-level transaction state, metadata cache, and loading queues. * Starlet Dashboard: Crucial for your setup as it tracks the raw latency and throughput of Azure Blob (FSLIB) operations. ────────── 2. Specific Metrics to Diagnose "Stuck" Transactions When transactions have a
CommitTime
but no
PublishTime
(or no
FinishTime
), look at these metrics on the Leader FE: *
starrocks_fe_txn_publish_schedule_latency_ms
: If this is high, the transaction is committed but waiting in the FE's internal queue. This usually means the
agent-task-pool
is saturated. *
publish_version_queue_count
: Monitor this value. If it is consistently high (e.g., > 100), the FE is failing to push "Publish Version" tasks to the CNs fast enough. *
starrocks_fe_txn_publish_execute_latency_ms
: If this is high, the CN nodes are receiving the tasks but taking a long time to execute them (likely due to the storage latency below). *
starrocks_fe_txn_publish_ack_latency_ms
: If this is high, the CNs have finished the work, but the FE is taking a long time to record the final metadata update back into its image/journal. ────────── 3. Metrics to Diagnose Slowness (20m -> 4h) Given your switch to PK tables with a 64-byte string on Azure Blob, these metrics on the CN nodes are critical: *
fslib_s3_single_upload_latency
: (Even on Azure, this often maps to Starlet's object upload metrics). If the P99 latency is > 100ms, your inserts will slow down significantly as every "version" must be flushed to the blob. *
pk_index_sst_read_error_total
/
pk_index_sst_write_error_total
: High values here indicate that the Cloud Native Persistent Index is failing to communicate with Azure Blob. *
update_primary_index_bytes_total
: Monitor the memory usage of your primary key index. If this is growing too large, it may cause the CN to thrash or swap. *
fslib_cache_hit_ratio
: Since you are using
datacache.enable = true
, a low hit ratio (< 80%) means your queries and PK index lookups are constantly hitting Azure Blob, which is orders of magnitude slower than the local cache. ────────── 4. Prevention and Thresholds To prevent this in the future, set up alerts for these specific thresholds: Metric | Threshold (Alert if...) | Action
publish_version_queue_count
| > 200 | Increase FE
lake_publish_version_max_threads
.
fslib_read_io_latency
(P99) | > 500ms | Check Azure Blob storage account limits or throttling.
lake_compaction_score
| > 100 | Ingestion is faster than compaction; consider slowing down inserts.
starrocks_fe_txn_publish_latency_ms
| > 60s | Investigate network/storage latency between FE and CNs. Why it might be happening now With 60M records/day and a 64-byte string PK, your Cloud Native Persistent Index creates many small files on Azure Blob. * If your Azure Blob Storage Account is reaching its IOPS or throughput limit, the
Publish Version
phase (which writes the final metadata and index files) will stall. * Prevention: Ensure your 19M record inserts are bundled into a single transaction. Many small
INSERT
statements will multiply the metadata overhead on Azure Blob exponentially. Referencesbest_practices/primarykey_table.mdtable_design/table_types/primary_key_table.md
g
@Rocky the specific error we see on these transactions is
Fail to publish partition 2799322 error Fail to publish version for tablets:[[2799332, 2799328, 2799325, 2799326, 2799329, 2799324, 2799327, 2799331, 2799330, 2799333, 2799323]], error msg: delvec inconsistent tablet:2799323 rssid:66 #old:366278 #add:26526 #new:392800 old_v:27 v:32, host: kube-starrocks-cn-1...
it's bizzare because our ETL process ran for several days with no issue and processed billions of records then hit this and got jammed up
r
The error message
delvec inconsistent ... #old:366278 #add:26526 #new:392800
is a low-level data integrity check failure within StarRocks' Primary Key storage engine. The Cause: Delete Vector Mismatch StarRocks uses Delete Vectors (delvec) to track which rows in older files have been logically deleted by newer updates. When applying a new batch of data (Publish phase), the system performs this check:
Existing Delete Markers (old) + New Delete Markers (add) == Total Markers in New Version (new)
In your case:
366278 + 26526 = 392804
. However, the system calculated
392800
. The discrepancy is 4 rows. This mismatch causes the
LOG(FATAL)
or a failed publish task because the system refuses to write inconsistent metadata. This typically happens due to a race condition between a write transaction and a background compaction task in shared-data mode. While you are on v4.09, which includes many fixes, this specific inconsistency suggests that the Cloud Native Persistent Index and the Metadata service on Azure Blob have diverged for those specific tablets. ────────── How to Fix It 1. Immediate Recovery (Partition Level) Because this is a metadata inconsistency on specific tablets, the cleanest way to "un-jam" the system is to remove the corrupted partition and reload it. * Identify the partition: Your error mentions
partition 2799322
. * Action:
Copy code
sql
    -- Drop the specific partition that is stuck
    ALTER TABLE <table_name> DROP PARTITION <partition_name>;
    -- Then reload the data for that period.
_Note: Since your RAW table is Duplicate Key (no corruption there), you can simply re-run the
INSERT INTO C_table SELECT ... FROM RAW_table
for that day._ 2. Rebuild the Persistent Index If dropping the partition is not ideal, you can try forcing StarRocks to rebuild the index files on Azure Blob, which may resolve the calculation error:
Copy code
sql
-- This forces the CN to re-read the data and re-generate the index
ALTER TABLE <table_name> REBUILD INDEX;
(Check your specific version's support for this command in shared-data mode; if it's not supported, dropping the partition is the standard path). 3. Adjust Concurrency Settings To prevent the race condition between write and publish in the future, try disabling "Batch Publish" which is often where these race conditions occur:
Copy code
sql
-- Run on FE to reduce the risk of batch-publish races
ADMIN SET FRONTEND CONFIG ("lake_enable_batch_publish_version" = "false");
Note: This might slightly increase the time it takes to finish a transaction, but it is much safer for data consistency in high-concurrency environments. 4. Address the 64-byte String PK You mentioned a
64-byte string
unique identifier in your Primary Key. * Observation: Long strings in a Primary Key significantly increase the size and complexity of the Persistent Index. * Recommendation: If possible, hash this
car_row_id
into a
BIGINT
or use a shorter ID. Large string keys are more prone to hitting internal memory/buffer limits during the
apply
phase, which can contribute to these types of inconsistencies. Summary of Why Queries Slower (20m -> 4h) The slowness is a direct symptom of this metadata jam. When a transaction is "stuck" in the publish phase: 1. Version Gaps: New transactions cannot become visible because they must wait for the stuck version (e.g., v27) to finish. 2. Lock Contention: The FE keeps the transaction record open, holding metadata locks that slow down other
SHOW
or
INSERT
commands. 3. Retry Storm: The CNs and FE are likely retrying the failed publish in the background, consuming IOPS on your Azure Blob storage and CPU on your CNs. Next Step: Check
fe.log
for the keyword
inconsistent
and
failed to publish
. If you see hundreds of these, dropping and recreating the affected partition is the most reliable way to clear the metadata corruption. References
g
@Rocky any clue why this would happen seemingly out of the blue?
r
The
delvec inconsistent
error you're seeing is a known, albeit rare, state where the metadata tracking deleted rows (Delete Vectors) becomes out of sync with the actual data files. Here is why this typically happens "out of the blue" and what the root causes are: 1. The "Out of the Blue" Trigger: Compaction vs. Publish This error is almost always caused by a race condition between a background Compaction task and a foreground Publish task (the final stage of your
INSERT
). * Why now? After several days of ingestion, the number of "versions" or small files in your 'C' table likely reached a threshold that triggered a large-scale background compaction. * The Conflict: If a compaction task merges files while a high-concurrency insert is trying to calculate which rows to delete in those same files, a calculation mismatch can occur. In shared-data mode, if one node fails to update the metadata service (on Azure Blob) atomically, the system gets stuck with an inconsistent "view" of the data. 2. Version Gaps in Shared-Data Mode In a shared-data (Cloud Native) architecture, StarRocks requires strict version continuity. * If transaction
N
hits the
delvec inconsistent
error, it fails to "Publish." * Transactions
N+1
,
N+2
, etc., will successfully "Commit" but stay in a
COMMITTED
state forever because they are waiting for the "gap" at version
N
to be filled. * Result: This is why your transactions are taking 2 days; they aren't actually working—they are queued behind a broken version. 3. Azure Blob Latency & 64-byte Keys Your use of a 64-byte string as a Primary Key significantly amplifies this risk: * Index Size: A 64-byte PK makes the Cloud Native Persistent Index much larger. Every time a new batch is "Applied," StarRocks must fetch and update this index from Azure Blob. * I/O Pressure: If Azure Blob experiences even a momentary latency spike or throttling while updating these large index/delvec files, the internal transaction timeout can trigger, leading to a partial metadata write—the primary cause of "inconsistency." ────────── How to Fix and Prevent Step 1: Clear the Blockage (The "Clean Slate") Since the metadata is inconsistent, the FE cannot "heal" it automatically. * Identify the bad partition: (From your error:
2799322
). * Drop and Reload: The fastest fix is to
ALTER TABLE ... DROP PARTITION ...
. This clears the bad metadata. Then, re-insert that day's data from your RAW (Duplicate Key) table. Step 2: Tune for Stability To prevent this race condition, adjust these settings in your
fe.conf
(requires restart):
Copy code
properties
# Reduce the concurrency of publish tasks to ensure atomicity
lake_publish_version_max_threads = 32

# (If supported in your specific 4.x sub-version)
# Disable batching if you see frequent delvec errors
lake_enable_batch_publish_version = false
Step 3: Optimize the Primary Key If you continue to use a 64-byte string as a PK: * Bucketing: Ensure your tablet count is not too high. If each partition has hundreds of tablets, you are creating thousands of small
delvec
files on Azure Blob, which increases the chance of a write failure. Aim for ~1GB-5GB per tablet. * Batching: Instead of frequent small inserts, group your 19M records into 1 or 2 large batches. This reduces the number of metadata "Publish" events and the chance of colliding with background compaction. Summary of Diagnosis The slowness (20m -> 4h) is likely due to the FE and CNs endlessly retrying the "Publish" for the inconsistent version
27
, which blocks all subsequent transactions. Once you drop the offending partition, your ingestion speed should return to normal.
g
@Rocky my etl process is setup where I will write to several partitions in my PK'ed target table, then in the next query, I might write to several of the same partitions, is this a problematic pattern?
r
Writing to the same partitions in back-to-back queries is a very common pattern in ETL, but for a Primary Key table in shared-data mode, it can become problematic if the frequency and volume are high. Here is why this pattern likely triggered your
delvec inconsistent
error and how to optimize it: 1. The "Commit Serialization" Bottleneck In StarRocks shared-data mode, the Frontend (FE) serializes transaction commits at the partition level to ensure data consistency. * The Conflict: When Query A and Query B both target the same partition, Query B must wait for Query A to finish its "Publish Version" phase. * The Risk: If Query A is large (e.g., your 19M records), it takes time to update the Persistent Index and write the Delete Vectors to Azure Blob. If Query B starts immediately, the FE may try to "batch" these versions or the CN nodes may face lock contention while trying to read the index that Query A is still finalizing. 2. High "Compaction Score" Every time you write to a partition, you create a new "version" (a set of small files). * The Problem: If you write to the same partitions multiple times in a short window, you quickly accumulate many small versions. * The Result: This triggers Compaction (the background process that merges these versions). In shared-data mode, if compaction is running on the same tablets you are currently writing to, it increases the likelihood of the race condition that causes the
delvec inconsistent
error. * Detection: Check
SHOW PROC '/transactions/<db_id>/running';
. If you see the message
Partition's compaction score is larger than 100.0, delay commit
, your ETL is outrunning the background maintenance. 3. Recommendations for your ETL To keep your process stable with your 64-byte string PKs on Azure Blob: * Consolidate Writes: Instead of several queries writing to the same partitions in sequence, try to use a single
INSERT INTO ... SELECT ...
that joins or unions all your source data first. One large transaction is significantly safer and faster than five smaller ones. * Increase Compaction Concurrency: Since you are on shared-data, the CN nodes need more "muscle" to keep up with the metadata churn.
Copy code
properties
    # On CN nodes (be.conf)
    compact_threads = 8  # Increase from default
* Use "Batch Publish" cautiously: As mentioned before, if you have high-frequency writes to the same partitions, disabling the FE's internal batching of version publishing can prevent the specific
delvec
calculation error you saw:
Copy code
sql
    ADMIN SET FRONTEND CONFIG ("lake_enable_batch_publish_version" = "false");
* Check Tablet Health: Use
SHOW TABLET FROM <table_name>
to see how many versions (
VersionCount
) exist per tablet. If this number is consistently > 50-100, you need to slow down the write frequency or increase compaction resources. Summary The pattern isn't "forbidden," but it is high-pressure. Your
delvec inconsistent
error was essentially a "collision" between two updates (or an update and a compaction) that both tried to modify the same Delete Vector on Azure Blob at the same time. Consolidating your ETL into fewer, larger transactions is the best architectural fix. Referencestable_design/table_types/primary_key_table.mdfaq/operation_maintenance_faq.md
g
@Rocky I dropped and recreated a partition and things went smoothly briefly then same error. The problem is I'm seeing trouble writing to a partition that was last written to 2 days ago, why would that be a problem now, that seems like plenty of time to resolve compactions and such.
r
The reason a partition last written to 2 days ago is suddenly failing now is because the inconsistency isn't necessarily in the data, but in the Metadata/Index that StarRocks uses to track that data. In StarRocks Shared-Data (Lake) mode, even when a partition is idle, several background processes or "Global" index updates can still affect it. Here is why your 2-day-old partition is "inconsistent" the moment you touch it again: 1. Background Compaction (The Silent Actor) Even if you haven't written to that partition for 2 days, StarRocks runs background compaction on the object store (Azure Blob). * The Scenario: A compaction task might have merged small files in that 2-day-old partition yesterday. * The Bug: If that compaction task hit a race condition or failed to update the Persistent Index correctly, the metadata for that partition became "poisoned." * The Discovery: You only see the error now because the "Publish" phase of your new write is the first time the system has tried to validate the Delete Vector counts for that tablet since the compaction happened. 2. Persistent Index vs. Delete Vectors Your error shows a 4-row discrepancy (
#old + #add != #new
). This calculation is driven by the Persistent Index (the map that says "Key X is in Segment Y"). _ If the Persistent Index file on Azure Blob was corrupted or didn't sync properly during a previous operation, it will tell the CN: _"You need to delete 392,804 rows."* * But when the CN looks at the actual data segments, it only finds 392,800. * Why it recurs after a drop/recreate: If your ETL process involves cross-partition updates (e.g., an incoming row has a primary key that exists in a different partition), StarRocks must go to that old partition to mark the old row as deleted. If the index has a logic bug handling your 64-byte string keys at scale, it will keep generating these small mismatches. 3. The "Lake Batch Publish" Race There is a known issue in some 3.x and 4.x versions where the FE tries to "batch" the publishing of multiple transactions to increase throughput. * When multiple concurrent
INSERT
or
UPDATE
operations target the same set of tablets, the batch-publish logic can occasionally double-count or miss delete markers in the metadata. * This explains why it worked "briefly" after your recreate and then failed again: As soon as your ETL ramped back up to high concurrency, the race condition returned. ────────── Recommended "Nuclear" Fix & Investigation Since dropping the partition didn't permanently fix it, you need to stabilize the metadata layer: 1. Disable Batch Publishing (Highest Priority): This is the most common fix for recurring
delvec inconsistent
errors in Lake mode. It forces the FE to publish versions one by one, eliminating the race condition.
Copy code
sql
    ADMIN SET FRONTEND CONFIG ("lake_enable_batch_publish_version" = "false");
2. Clear the Persistent Index Cache: It is possible your CN nodes are holding a "stale" version of the index in their local disk cache (
storage/persistent_index/
). * If possible, restart a CN node one by one. When it comes back up, it will pull a fresh (and hopefully consistent) version of the index from Azure Blob. 3. Check for "Global" Key Collisions: Are you sure your incoming data doesn't have keys that already exist in that 2-day-old partition? If your ETL is "moving" data between partitions (e.g., updating a record's date which changes its partition), this triggers complex metadata updates that are prone to this error. 4. Check FE Logs for "Conflict": Search your
fe.log
specifically for the
tablet_id
mentioned (
2799323
). Look for any messages saying
compaction conflict
or
version already exists
. This will confirm if background compaction is the culprit.
Summary: The 2-day gap doesn't matter because the "truth" (the Index) is stored on Azure Blob and is constantly being managed by background tasks. The "4-row" mismatch is a sign that the Index thinks there are 4 more records to delete than actually exist in the physical files. Disabling batch publish is your best bet to stop this from happening again. Referencesdeployment/shared_data/azure.mdfaq/shared_data_faq.md
g
@Rocky how can i tell if my nodes persistent_index on the PVC which would not force a recreate, correct?
r
In StarRocks shared-data (Lake) mode, the Persistent Index for Primary Key tables is designed to be highly durable, but your suspicion is correct: if you are running on Kubernetes with a PVC, a simple pod restart will not force a clean "recreate" of that index. Here is how to tell where it lives and how to force a refresh: 1. How to tell if it's on a PVC By default, StarRocks caches/stores the Persistent Index on the local disks of your CN (Compute Nodes) to speed up lookups. * The Path: Check your
cn.conf
. The index is stored under the directory specified by
storage_root_path
. * Inside that path, look for a folder named
persistent
(e.g.,
/opt/starrocks/storage/persistent/
). * The PVC check: Run
kubectl get pod <cn-pod-name> -o yaml
and look at the
volumeMounts
section. If the path matching your
storage_root_path
is mounted to a
persistentVolumeClaim
, then the index is on a PVC and will survive restarts. 2. Why a restart isn't enough When a CN pod restarts, it looks at that
persistent
directory. If it finds existing index files, it simply reloads them. * If the "4-row mismatch" metadata error is baked into those local index files, the CN will just reload the same corrupted state. * In shared-data mode, the "Source of Truth" is technically on Azure Blob, but the local CN cache can get "stuck" if the local file is present but inconsistent with the remote version. 3. How to Force a "Clean Slate" (Recreate) To truly force the node to rebuild the index from the remote storage (or from scratch), you must manually remove the local cache before the restart. The "Clean Slate" Procedure: 1. Scale down the CN deployment to 0 (or stop the specific CN pod). 2. Delete the index files on the PVC. You can do this by mounting the PVC to a temporary "maintenance" pod or by exec-ing into the pod before it shuts down:
Copy code
bash
    # From inside the CN pod
    rm -rf /opt/starrocks/storage/persistent/*
_(Note: Ensure you only delete the contents of the
persistent
folder, not the entire
storage_root_path
if you also have Data Cache you want to keep.)_ 3. Scale up the CN deployment. 4. Important Configuration Check Check if your cluster is configured to store the index only in the cloud (v3.3.2+). If you have this set, the local PVC is just a temporary cache:
Copy code
sql
-- Check this in your FE/BE configs
ADMIN SHOW FRONTEND CONFIG LIKE '%persistent_index%';
If you see a setting like
lake_persistent_index_type = CLOUD
, the CN will automatically try to sync from Azure Blob. However, if it's
LOCAL
, the CN relies heavily on the files on that PVC. Summary If you see the
delvec inconsistent
error and you have PVCs, restarting the pod is like rebooting a computer without clearing the cache. To fix it, you must delete the contents of the
storage/persistent/
directory on the PVC so the node is forced to pull fresh metadata from the FE and Object Storage. Referencestable_design/table_types/primary_key_table.mdadministration/management/BE_configuration.mddeployment/shared_data/azure.md Referencesusing_starrocks/caching/block_cache.mddata_source/data_cache_troubleshooting.mddeployment/upgrade.mdusing_starrocks/caching/query_cache.mdadministration/management/BE_configuration.mddeployment/downgrade.md
g
@Rocky I'm now wondering if this issue continues to pop up because of the index on pvc, if a node has to restart, it may keep the old index instead of building a new one, could that be it?
r
Yes, your suspicion is likely correct. If you are using a Persistent Index in LOCAL mode on a Kubernetes PVC, you are effectively "freezing" the index state across restarts. This can be problematic in a shared-data (lake) environment for several reasons: 1. The "LOCAL" Index Persistence Trap StarRocks Primary Key tables have two main types of Persistent Index for shared-data clusters: *
LOCAL
(Default in older versions/configurations):
The index is stored entirely on the CN node's local disk (
storage_root_path/persistent/
). In Kubernetes, if this path is on a PVC, the CN pod will reload the exact same index files upon restart. *
CLOUD_NATIVE
(Recommended for Shared-Data):
The index "Source of Truth" is stored on your object storage (Azure Blob). The local disk is used only as a cache. Why this matters: If a metadata mismatch (like your "4-row" error) gets written into the local index files on the PVC, restarting the pod won't help. The pod wakes up, sees the existing index on the PVC, and says, "Great, I don't need to rebuild anything," and continues using the corrupted metadata. 2. How to Check Your Index Type Run the following command to see how your table is configured:
Copy code
sql
SHOW CREATE TABLE <your_table_name>;
Look for these properties: *
"enable_persistent_index" = "true"
*
"persistent_index_type" = "LOCAL"
<-- If you see this, the PVC is likely the issue. 3. Why
CLOUD_NATIVE
is the Solution
For shared-data clusters, StarRocks highly recommends using
CLOUD_NATIVE
persistent indexes. * Self-Healing: If a node restarts or a cache is lost, the CN simply pulls the latest consistent index from Azure Blob. * Consistency: Since the index is versioned alongside your data in the cloud, it is much harder for a single node's local disk state to cause a cluster-wide "delvec inconsistent" error. 4. How to Fix It If you find you are using
LOCAL
on a PVC, you have two options: Option A: Switch to Cloud Native Index (Recommended) You can alter the table to use the cloud-native index. This will move the index "Source of Truth" to Azure Blob:
Copy code
sql
ALTER TABLE <table_name> SET ("persistent_index_type" = "CLOUD_NATIVE");
Note: This might trigger a background task to upload the index; monitor
SHOW ALTER TABLE COLUMN
to see progress.
Option B: The "Clean Start" (Manual PVC Wipe) If you must stay with
LOCAL
, you need to manually invalidate the PVC cache to force a rebuild from the data: 1. Stop the CN pod(s). 2. Mount the PVC to a "debug" pod or use a script to delete all files inside the
persistent/
directory. 3. Restart the CN pod. 4. StarRocks will see the index is missing and will be forced to rebuild it by scanning the data segments on Azure Blob, which should resolve the "4-row" mismatch. Summary The PVC is doing its job (preserving data), but in this specific case, it’s preserving a "corrupted" or "out-of-sync" local view of your metadata. Switching to
"persistent_index_type" = "CLOUD_NATIVE"
is the architectural fix to prevent the PVC from being a single point of metadata failure. Referencesbest_practices/primarykey_table.mdadministration/management/BE_configuration.mdfaq/shared_data_faq.md Referencesbest_practices/primarykey_table.mdadministration/management/BE_configuration.mdadministration/management/FE_configuration.mdtable_design/indexes/inverted_index.md
g
@Rocky ok nevermind, our properties are
Copy code
ORDER BY (event_time)
PROPERTIES (
    "compression" = "LZ4",
    "datacache.enable" = "true",
    "enable_persistent_index" = "true",
    "persistent_index_type" = "CLOUD_NATIVE"
);
r
Since you are using
CLOUD_NATIVE
persistent indexes, the "Source of Truth" for your primary key index lives in your Azure Blob storage, not on the local PVC. However, the recurring error on a 2-day-old partition suggests that the metadata for that partition is being modified (or failing to be modified) even when you aren't explicitly loading data into it. Here is why a 2-day-old partition is failing and how to stop the cycle: 1. The "Global" Primary Key Effect In a StarRocks Primary Key table, uniqueness is enforced across the entire table, not just the current partition. * The Scenario: If your new data today contains a primary key that already exists in that 2-day-old partition, StarRocks must go back to the old partition and mark the old row as "deleted" (via a Delete Vector). * The Error: Your error (
#old + #add != #new
) is a metadata checksum failure. It means that when the FE/CN tried to update the delete markers for that 2-day-old partition, the math for the "total deleted rows" didn't add up compared to what was previously recorded. 2. Why it keeps happening (The "Batch Publish" Race) In shared-data (Lake) mode, StarRocks attempts to optimize performance by batching the "Publish" phase of multiple transactions. * There is a known issue where high-concurrency updates can cause the FE to incorrectly sum up the
delvec
counts when multiple transactions try to "delete" rows from the same old tablet at the same time. * The Fix: Disable batch publishing to force strict, one-by-one metadata updates. This is the most successful fix for recurring
delvec inconsistent
errors in Lake mode.
Copy code
sql
    ADMIN SET FRONTEND CONFIG ("lake_enable_batch_publish_version" = "false");
3. Background Compaction Even if no writes happen, StarRocks runs background compaction on old partitions to merge small files. * If a compaction task for that 2-day-old partition was scheduled recently and hit a bug while updating the
CLOUD_NATIVE
index on Azure, the partition's metadata becomes "poisoned." * You only see the error when you next attempt a write that triggers a PK lookup in that partition. 4. The PVC "Ghost" Cache Even with
CLOUD_NATIVE
, the CN nodes use the local disk (your PVC) as a cache for those index files. _ If a CN node has a corrupted _cached* version of the index on its PVC, it might keep using it even after a restart. * To rule this out: You should perform a "Deep Clean" on at least one CN node. Scale it down, manually delete the contents of the
storage/persistent/
directory on the PVC, and scale it back up. This forces it to pull a fresh, verified index from Azure Blob. Summary Checklist to Resolve: 1. Run Repair: Try to let StarRocks fix the metadata state for that specific partition by rolling it back to the last known healthy version:
Copy code
sql
    ADMIN REPAIR TABLE <table_name> PARTITION (<old_partition_name>);
2. Disable Batch Publish: Run the
ADMIN SET FRONTEND CONFIG
command mentioned above. 3. Check for Cross-Partition Upserts: Verify if your ETL is sending rows that would overwrite data in those older partitions. If so, the metadata pressure on those partitions is much higher than you'd expect for "idle" data. 4. Verify StarRocks Version: If you are on a version earlier than v3.2.10 or v3.3.3, there were significant fixes for
CLOUD_NATIVE
index consistency that address this exact "4-row mismatch" logic. Recommendation: If disabling
lake_enable_batch_publish_version
doesn't stop the recurrence within 24 hours, it is likely a bug in the compaction logic for your specific version, and you should check the
<http://be.INFO|be.INFO>
logs for "compaction" related errors on that specific
tablet_id
. Referencesadministration/management/resource_management/Replica.md
g
@Rocky what is the tradeoff in setting
lake_enable_batch_publish_version
to false
r
Setting
lake_enable_batch_publish_version
to
false
changes how StarRocks commits (publishes) data transactions to your shared-data cluster. While it is often used as a fix for the "delvec inconsistent" metadata errors you are seeing, there are specific trade-offs: 1. The Performance Trade-off (Throughput) The primary reason this setting exists is to handle high-concurrency writes (e.g., hundreds of small
Stream Loads
per second). * With
true
(Default):
The Frontend (FE) bundles multiple completed transactions into a single "Publish RPC." This significantly reduces the overhead on the FE and the metadata service. * With `false`: Every single transaction must wait for its own dedicated RPC to finish. In high-concurrency environments, this can create a bottleneck at the FE, leading to "Transaction Queue Full" errors or much lower total ingestion throughput (KB/s). _ _Note: In benchmarks, disabling this can drop throughput by 5x–8x during heavy parallel loading.* 2. Visibility Latency vs. Throughput * Visibility Latency: When set to
false
, an individual transaction might actually become "visible" for querying slightly faster because it doesn't have to wait for other transactions to fill a batch. * Overall Ceiling: However, because the system is doing more "work" per transaction, the total number of transactions the cluster can handle per minute decreases. 3. Impact on FE Stability * If you have a very high volume of small loads, setting this to
false
will increase the CPU and Thread usage on your FE. Monitor the
lake_publish_version_max_threads
usage if you make this change. 4. Why it fixes your error The "delvec inconsistent" error often stems from a race condition or a logic error in how the FE calculates the cumulative "Delete Vector" count when it tries to merge metadata for 10 different transactions at the exact same moment. By setting this to
false
, you are essentially forcing StarRocks to serialize these updates, ensuring that each transaction's metadata is built strictly on top of the one before it. Summary Recommendation * If you have moderate load: You likely won't feel any negative impact. Setting it to
false
is a very safe way to ensure data consistency while you investigate the root cause of the metadata mismatch. * If you have extreme real-time load: You may see your ingestion speed slow down. In that case, the long-term solution is to upgrade to a version (like v3.2.10+ or v3.3.3+) where the batching logic for
CLOUD_NATIVE
indexes was significantly patched, allowing you to turn batching back on safely. Referencesadministration/management/FE_configuration.mdknowledge/usage/load/shared_data_batch_ingestion.mdbest_practices/primarykey_table.mdadministration/management/BE_configuration.mddata_source/datalake_faq.mdadministration/management/FE_configuration.mdadministration/management/FE_configuration.mdadministration/management/FE_configuration.mdadministration/management/FE_configuration.mdadministration/management/FE_configuration.mdknowledge/usage/load/shared_data_batch_ingestion.md
g
@Rocky we are on 4.0.9, is this still a fix?
r
Yes, this is still a valid fix for version 4.0.9. Even though 4.0.9 is a very recent release (April 2026), the underlying mechanism for batching transaction commits in shared-data clusters still relies on this configuration. If you are seeing recurring "delvec inconsistent" or metadata mismatch errors, setting this to
false
remains the primary "safety switch" for the following reasons: 1. It Eliminates Commit-Time Race Conditions The error usually happens during the Publish phase, where the Frontend (FE) calculates the new metadata state. When
lake_enable_batch_publish_version
is
true
(the default), the FE tries to merge metadata for multiple concurrent transactions into a single update. In complex Primary Key scenarios—especially involving older partitions being updated by new "upserts"—this batching logic can occasionally hit a race condition that results in the "4-row mismatch" math error. By setting it to
false
, you force StarRocks to serialize these updates, ensuring each transaction is published strictly one-by-one, which eliminates the potential for a batching math error. 2. Is there a Performance Penalty in 4.0.9? In 4.0.9, the FE is significantly more optimized than in the 3.x series. While setting this to
false
will increase the number of RPC calls, the 4.x FE can handle a higher volume of individual publishes than older versions. * Recommendation: If your ingestion rate is under 50
Stream Load
jobs per minute, you likely won't notice any performance degradation at all. * High Load: If you are doing hundreds of small loads per minute, monitor your FE CPU; you might need to slightly increase the interval between your load batches to compensate for the lost batching efficiency. 3. How to "Clean" the 2-Day-Old Partition Because you are using
CLOUD_NATIVE
, the mismatched metadata is now likely "committed" to your Azure Blob metadata logs. Simply changing the setting might not fix the existing mismatch on that 2-day-old partition. You should perform a manual repair:
Copy code
sql
-- This forces the FE to re-sync the metadata state for that partition
ADMIN REPAIR TABLE <table_name> PARTITION (<partition_name>);
4. Why it happened on 4.0.9 There was a specific fix in the 4.0.x branch (#71672) related to how
get_tablet_stats
repeatedly reloads TabletMetadata for Primary Key tablets. While 4.0.9 contains many fixes, the "delvec inconsistent" logic is notoriously sensitive to high-concurrency "Delete-then-Insert" patterns. Summary of your next steps: 1. Set the config:
ADMIN SET FRONTEND CONFIG ("lake_enable_batch_publish_version" = "false");
2. Repair the old partition: Run
ADMIN REPAIR
on the partition that is currently failing. 3. Check Compaction: If the error still pops up, check if
lake_compaction_max_tasks
is set too high, which might be putting too much concurrent pressure on the metadata service. Referencesadministration/management/FE_configuration.mdrelease_notes/release-4.0.mdbest_practices/primarykey_table.mdsql-reference/sql-statements/cluster-management/tablet_replica/ADMIN_REPAIR.md Referencesadministration/management/FE_configuration.mdknowledge/usage/load/shared_data_batch_ingestion.mdrelease_notes/release-4.0.mdsql-reference/System_variable.md
g
@Rocky i don't see things like
starrocks_fe_txn_publish_schedule_latency_ms
in the grafana dashboards, am I missing it or is it not present?
r
The metric
starrocks_fe_txn_publish_schedule_latency_ms
is indeed present in StarRocks 4.0.x, but it is likely missing from your dashboard for two specific reasons: 1. It is disabled by default In version 4.0, StarRocks introduced a more granular way to report transaction metrics. To prevent overhead, these metrics are not reported unless you explicitly define which "groups" of transactions you want to track. You need to set the following FE configuration (this can be done dynamically):
Copy code
sql
ADMIN SET FRONTEND CONFIG ("txn_latency_metric_report_groups" = "stream_load,routine_load,insert,compaction");
* Note: Since you are in Lake (shared-data) mode, including
compaction
is highly recommended, as background compaction also uses the transaction/publish pipeline. 2. It is only reported by the Leader FE This metric is only exposed by the Leader FE node. * If your Grafana dashboard is looking at a specific Follower FE or using an aggregate that doesn't filter for the leader, you may see "No Data." * In your Prometheus query, ensure you filter for
is_leader="true"
. How to verify it exists Once you have set the config above, you can verify the metric is being generated by hitting the FE metrics endpoint directly:
Copy code
bash
curl http://<LEADER_FE_IP>:<HTTP_PORT>/metrics | grep starrocks_fe_txn_publish_schedule_latency_ms
Why this metric matters for your issue Since you are debugging
delvec inconsistent
errors and considering disabling `lake_enable_batch_publish_version`: * High Schedule Latency: If this metric is high (e.g., > 100ms), it means transactions are queuing up waiting to be published. * The Impact of your change: If you set
lake_enable_batch_publish_version
to
false
, you will likely see this specific metric increase, because the FE can no longer "cheat" by bundling multiple transactions into one publish task. It confirms the "bottleneck" trade-off we discussed. Summary: Update your
txn_latency_metric_report_groups
config, and the metric should appear in Prometheus/Grafana shortly after. Referencesadministration/management/monitoring/metrics.mdadministration/management/FE_configuration.mdrelease_notes/release-4.0.md Referencesadministration/management/monitoring/metrics.mdadministration/management/FE_configuration.md
g
@Rocky which of the dashboards would these metrics be in?
r
In StarRocks 4.0.9, the metrics you are looking for are primarily located in the Shared-data Dashboard (sometimes titled "Lake Dashboard") and the FE Dashboard. Because
starrocks_fe_txn_publish_schedule_latency_ms
and its related transaction metrics were introduced in v4.0, they are often grouped into the following sections: 1. Shared-data Dashboard (Recommended) If you are using the official shared-data dashboard template (available in the StarRocks GitHub extra/grafana folder), look for a row titled "Publish Version" or "Ingestion / Loading". * Panel Name: Usually titled "Publish Version Latency" or "Transaction Publish Phase Latency." * What it shows: It typically visualizes the breakdown of the publish phase, including the "Schedule" (wait time) and "Execute" (active time) components. 2. FE Dashboard In the standard FE dashboard, these metrics are often found under the "Transaction" or "Metadata Management" section. * Panel Name: Look for "Transaction Publish Schedule Latency" or a heatmap/quantile graph showing "FE Transaction Latency (by Phase)." Why they might still be missing from the UI Even if the metrics exist in Prometheus (after setting
txn_latency_metric_report_groups
), they won't appear in Grafana if your dashboard template is from an older version (e.g., v3.x). To resolve this: 1. Verify the Metric exists: Run
curl http://<FE_LEADER_IP>:8030/metrics | grep txn_publish_schedule
to ensure the FE is actually exporting it. 2. Update your Dashboard: Download the latest v4.0 JSON templates from the StarRocks GitHub. 3. Manual Query: If you don't want to re-import the whole dashboard, you can create a custom Grafana panel using this PromQL:
Copy code
promql
    # 99th percentile of publish scheduling delay
    histogram_quantile(0.99, sum(rate(starrocks_fe_txn_publish_schedule_latency_ms_bucket{is_leader="true"}[5m])) by (le, type))
Summary of Dashboard Sections Dashboard | Category/Row | Panel Goal Shared-data | Publish Version | Monitor the latency and queue of shared-data metadata commits. FE | Transaction | Monitor the end-to-end performance of loads (Stream, Routine, etc.). Referencesadministration/management/monitoring/metrics.mdadministration/management/FE_configuration.mdrelease_notes/release-4.0.mdadministration/management/monitoring/monitor_and_alert.md Referencesadministration/management/monitoring/metrics.mdadministration/management/FE_configuration.md
g
@Rocky in the
Publish Version
section of the shared-data general dashboard, I see
Publish Tablet Version Latency / QPS
and
Queued Publish Tablet Tasks
are these the right metrics for this issue?
r
Yes, those are the correct high-level metrics for monitoring the health of your ingestion pipeline and the publish process. Here is how they map to the technical issue you are troubleshooting: *1. Queued Publish Tablet Tasks* * Source Metric:
publish_version_queue_count
* What it tells you: This is the size of the FE's internal thread pool queue for publish tasks. * Why it matters for your fix: If this number is consistently high (greater than 0), it means the FE cannot keep up with the volume of incoming transaction commits. When you set
lake_enable_batch_publish_version = false
, you are intentionally making each publish task "smaller" (one transaction at a time) but "more frequent." This can cause this queue to grow. If this queue hits its limit, you will see
publish version timeout
errors. *2. Publish Tablet Version Latency / QPS* * Source Metric:
starrocks_fe_txn_publish_latency_ms
(usually) * What it tells you: The "Latency" shows how long it takes for a transaction to go from "Committed" to "Visible." The "QPS" shows how many transactions are being finished per second. * Why it matters for your fix: * Latency: After disabling batching, keep an eye on the 99th percentile (P99) here. If latency spikes significantly (e.g., above 1-2 seconds), your "delvec inconsistent" error might stop, but your users might notice a "data lag" where rows they just loaded don't appear in queries immediately. * QPS: This should ideally match your ingestion rate (number of
Stream Load
or
Routine Load
jobs per second). Are they the "Right" ones? They are the "System Health" metrics, but they aren't the "Diagnostic" metrics. * The metrics you found tell you if the system is slow. *
starrocks_fe_txn_publish_schedule_latency_ms
(the one you were looking for) tells you why it is slow—specifically if the delay is happening in the scheduling logic (which is where the batching code lives) versus the execution (writing to the object store). Recommendation If you see Queued Publish Tablet Tasks rising after you set
lake_enable_batch_publish_version
to
false
, it means your FE is working harder to process transactions one-by-one. If it stays under control and your "delvec" errors stop, you have successfully stabilized the cluster. Summary: Yes, watch these two panels. If Queued Tasks stays near zero and Latency stays under 500ms-1s, your change to
false
is perfectly safe for your current load. Referencesadministration/management/monitoring/metrics.mdadministration/management/FE_configuration.mdknowledge/usage/load/shared_data_batch_ingestion.mdbest_practices/primarykey_table.md Referencesadministration/management/monitoring/metrics.md
g
@Rocky how about this one
Fail to publish partition 2799768 error Fail to publish version for tablets:[[2799774, 2799771]], error msg: prepare_primary_index: load primary index failed: Already exist: PersistentIndexMemtable<51> insert found duplicate key <KEY> old_val 498216518911 old_ver 28 new_val 498216518912
be/src/storage/lake/lake_persistent_index.cpp:308 _memtable->insert(n, keys, values, version)
be/src/storage/lake/lake_persistent_index.cpp:840 insert(pkc->size(), reinterpret_cast<const Slice*>(pkc->raw_data()), values.data(), rowset_version), host: kube-starrocks-cn-2.kube-starrocks-cn-search.kube-starrocks.svc.cluster.local
r
The error message you've shared is the root cause of the spikes you are seeing in the Grafana dashboards. It confirms that your
delvec
inconsistency is tied to a failure in the Primary Key Persistent Index during the publish phase. What this error means
Already exist: PersistentIndexMemtable<51> insert found duplicate key <KEY>
In StarRocks Shared-data mode, when you load data into a Primary Key table, the system must update an index to know which row versions are current. * The Conflict: The "PersistentIndexMemtable" is the memory-resident part of that index. This error means the system tried to "publish" a new version of a key, but it found that the key already existed in the index with a conflicting internal state. * The Versioning: You see
old_ver 28
and
new_val ...
. This usually implies a retry or a race condition. The FE thought version 28 was ready to be published, but the CN node (where the index lives) already had a record of a change for that key that didn't match the FE's instruction. Is this the "right" issue for the metrics? Yes. This error directly causes the metrics you found in the dashboard to look "bad": 1. Fail to publish version: This error causes the task to fail. 2. Queued Publish Tablet Tasks: Because the task failed, the FE will retry it. If many tablets hit this error, the retry queue fills up. 3. Publish Latency: As long as this "duplicate key" conflict exists, the transaction cannot finish, causing latency to skyrocket to minutes or hours (until the transaction eventually times out or is manually fixed). How to fix it Since you are seeing this specifically in
lake_persistent_index.cpp
, here is the recommended path: 1. Immediate Workaround (The one you are currently trying) Set
lake_enable_batch_publish_version = false
. * Why? Batching combines multiple transactions into one "publish" task. If Transaction A and Transaction B both modify the same Primary Key, batching them together can sometimes trigger this internal conflict if they aren't handled atomically by the index. Disabling batching forces them to be processed one-by-one, which is much safer and usually stops this error. 2. If the error persists for a specific tablet If a specific tablet ID (like
2799774
) is "stuck" and keeps throwing this error even after disabling batching, the index for that tablet may be corrupted on the local disk of the CN. * Action: You can try to clear the local persistent index cache for that tablet to force it to rebuild from the object store. _ _Note: In shared-data mode, the "source of truth" is the object store, so deleting the local index file is safe; it will be redownloaded/rebuilt.* Summary The
PersistentIndexMemtable
error is the "smoking gun." The Grafana metrics (Queued Tasks and Latency) are showing you the symptoms, but this log entry explains the disease. Setting
lake_enable_batch_publish_version = false
is the correct first step to stabilize this. Referencestable_design/table_types/primary_key_table.mdadministration/management/monitoring/metrics.mdadministration/management/FE_configuration.md Referencesfaq/loading/Loading_faq.mdadministration/management/monitoring/metrics.mdbest_practices/primarykey_table.mdtable_design/table_types/duplicate_key_table.mdtable_design/table_types/primary_key_table.md
g
@Rocky do i need to restart when applying lake_enable_batch_publish_version = false?
r
No, you do not need to restart the FE to apply this change.
lake_enable_batch_publish_version
is a mutable configuration, meaning it can be updated dynamically while the cluster is running. How to apply it Run the following SQL command as an admin user (e.g.,
root
):
Copy code
sql
ADMIN SET FRONTEND CONFIG ("lake_enable_batch_publish_version" = "false");
Important Notes: 1. Persistence: While the
ADMIN SET FRONTEND CONFIG
command takes effect immediately, it will be lost if the FE service restarts. To make the change permanent, you should also add/update this line in your
fe.conf
file on every FE node:
Copy code
properties
    lake_enable_batch_publish_version = false
2. Verification: You can verify that the setting has been applied by running:
Copy code
sql
    ADMIN SHOW FRONTEND CONFIG LIKE 'lake_enable_batch_publish_version';
3. Scope: This setting is handled by the FE Leader. Once you run the command, the Leader will stop batching publish tasks for shared-data tables immediately. Referencesadministration/management/FE_configuration.mdknowledge/usage/load/shared_data_batch_ingestion.md Referencesadministration/management/FE_configuration.mdknowledge/usage/load/shared_data_batch_ingestion.md Referencesadministration/management/FE_configuration.mdknowledge/usage/load/shared_data_batch_ingestion.md
g
@Rocky does 4.1.1 have any fixes that would help with these issues over 4.0.9?
r
Yes, upgrading to 4.1.1 (or even 4.0.10) addresses several critical bugs specifically related to delvec (Delete Vector) inconsistency and shared-data publish races that are present in 4.0.9. Here are the specific fixes and improvements in 4.1.1 that directly target the issues you are seeing: 1. Fix for "Delvec Inconsistency" with Batch Publish (#71049) A key fix in the 4.1 branch (and 4.0.10) addresses an issue where orphan delete vector entries were left behind when a write operation and a compaction occurred within the same publish batch. * Relevance: This is likely why you saw "delvec inconsistency" when
lake_enable_batch_publish_version
was set to
true
. This fix makes the batching mechanism much safer for Primary Key tables. 2. Fix for Shared-Data Transaction Log Races (#72237, #71992) There were races in the "combined transaction log" mode where legitimate logs were incorrectly classified as "orphans" and dropped. * Relevance: When logs are dropped or misclassified, the FE and the CN nodes (BEs) get out of sync regarding which versions of a key exist. This leads to the
Already exist: PersistentIndexMemtable insert found duplicate key
error you encountered, as the CN tries to insert a key version it mistakenly thinks is new or already handled. 3. Performance: Intra-Tablet Parallelism (New in 4.1) StarRocks 4.1 introduces Phase 1 of Large-Capacity Tablet Support, which includes parallelizing the Primary Key update and compaction pipeline within a single tablet. * Relevance: In 4.0.9, a single large tablet could become a bottleneck during the publish phase because updates were largely single-threaded per tablet. 4.1 allows the CN to process these updates in parallel, which should significantly reduce the
Publish Tablet Version Latency
you are monitoring in Grafana. 4. Stability fix for v4.1.1 specifically (#71825) If you are considering the 4.1 branch, v4.1.1 is a required upgrade over v4.1.0. * Warning: v4.1.0 had an unstable load order issue in container environments that could cause BE processes to fail to start reliably. This is fixed in 4.1.1. Summary Comparison Feature / Fix | v4.0.9 | v4.1.1 Delvec Batching Fix | Affected by #71049 | Fixed Txn Log Race Fix | Affected by #72237 | Fixed PK Parallelism | Single-threaded per tablet | Intra-tablet parallel updates Tablet Support | Standard limits | Optimized for 100GB+ tablets Recommendation: If you are currently on 4.0.9 and experiencing these errors, upgrading to 4.1.1 is highly recommended. It should allow you to re-enable
lake_enable_batch_publish_version = true
safely, which will lower your FE CPU overhead while the code fixes prevent the metadata inconsistencies you've been battling. Referencesknowledge/usage/load/shared_data_batch_ingestion.mdbest_practices/primarykey_table.mdadministration/management/monitoring/metrics.mdtable_design/table_types/primary_key_table.mdadministration/management/FE_configuration.mdfaq/loading/Loading_faq.md
g
@Rocky ok we are on 4.0.9 shared data managed with helm, do we need to do anything other than bump the versions of the fe's and cn's then deploy?
r
While bumping the version in your Helm
values.yaml
is the primary step, there are a few critical safety precautions you should take for a minor version jump (4.0 to 4.1) in Shared Data mode to ensure metadata consistency. 1. The Correct Order (CN then FE) In StarRocks, BEs and CNs are backward compatible with FEs. For a rolling upgrade to work without downtime: * Update CNs first: Change the image tag for the CNs in your Helm values and run
helm upgrade
. Wait for all CN pods to be
Running
and
Healthy
. * Update FEs second: After the CNs are done, update the FE image tag and run
helm upgrade
. 2. Mandatory Pre-Upgrade Steps Before you trigger the upgrade, run these SQL commands as an admin. These prevent the cluster from trying to move data around (balancing) while pods are restarting, which can lead to "tablet not found" errors during the transition.
Copy code
sql
-- 1. Disable balancing and scheduling
ADMIN SET FRONTEND CONFIG ("tablet_sched_max_scheduling_tablets" = "0");
ADMIN SET FRONTEND CONFIG ("tablet_sched_max_balancing_tablets" = "0");
ADMIN SET FRONTEND CONFIG ("disable_balance" = "true");
ADMIN SET FRONTEND CONFIG ("disable_colocate_balance" = "true");

-- 2. Create a fresh metadata image (Safety backup)
-- This ensures that if the FE fails to upgrade, you have a clean starting point.
ALTER SYSTEM CREATE IMAGE;
Note: Check
fe.log
to ensure the image creation finishes before starting the Helm upgrade.
3. Shared Data Specifics for 4.1 StarRocks 4.1 introduces Large-Capacity Tablet Support and internal changes to how the Persistent Index is stored (adding remote-storage mapper files). * Automatic Migration: These changes happen automatically as data is written/compacted in 4.1. You don't need to run manual migration scripts. * Downgrade limit: If you need to roll back, you can downgrade from 4.1 back to 4.0.9. However, the docs note that you cannot downgrade to any version below 4.0.6 due to metadata layout changes introduced in 4.1. 4. Helm Checklist 1. Avoid 4.1.0: Use 4.1.1 (or later). 4.1.0 has a known race condition in container environments where BE/CN processes fail to start. 2. Resources: 4.1's new features (like parallel compaction) may slightly increase CPU usage during heavy loads. Ensure your CN resource limits have a small buffer. 3. Persistence: Ensure your
lake_enable_batch_publish_version = false
setting is added to the
fe.conf
section of your Helm values so it isn't wiped out by the upgrade. Summary of Workflow 1. SQL: Disable balancing +
ALTER SYSTEM CREATE IMAGE
. 2. Helm: Update
values.yaml
with 4.1.1 image tags for CN. 3. Command:
helm upgrade <release> starrocks/kube-starrocks -f values.yaml
. 4. Wait: Ensure all CNs are healthy. 5. Helm: Update
values.yaml
for FE image tags. 6. Command:
helm upgrade ...
7. SQL: Re-enable balancing (set the 4 configs from step 2 back to their defaults). Referencesdeployment/upgrade.mdreleasenotes/release-4.1.mdadministration/management/FE_configuration.md Referencesdeployment/upgrade.mdquick_start/helm.md
g
Though @Rocky didn't you say we should keep
lake_enable_batch_publish_version = false
as true because the upgrade will work better with it?
r
I apologize for the confusion in my previous response. To be absolutely clear: keep it set to
false
during the actual upgrade process
, and only switch it back to
true
after the cluster is fully running on version 4.1.1. Here is why and how you should handle this specific flag: 1. Why keep it
false
during the upgrade?
While StarRocks 4.1.1 fixes the "delvec inconsistency" bug, the upgrade involves a period where your cluster is in a mixed state (some nodes on 4.0.9 and some on 4.1.1). * The batch publish logic requires coordination between the FE and the CNs. * Running a "batch publish" from a 4.1.1 FE to a 4.0.9 CN (or vice versa) during the rolling restart could trigger the very race conditions and inconsistency issues you are trying to avoid. * Keeping it
false
ensures that every transaction is published individually and conservatively while the cluster is unstable. 2. When to switch it to
true
?
Once your Helm deployment is finished and all FE and CN pods are healthy on version 4.1.1, you should re-enable it. This is where you get the performance benefits (lower FE CPU and higher ingestion throughput) without the risk of data inconsistency. Updated Workflow Recommendation: 1. Before Upgrade: Keep
lake_enable_batch_publish_version = false
in your
fe.conf
(via Helm
config
or
extraArgs
). 2. Perform Upgrade: Deploy 4.1.1 (CNs first, then FEs). 3. Post-Upgrade Verification: Run a few smoke tests/loads to ensure the
Already exist
errors have stopped. 4. Re-enable Optimization: Switch the flag to
true
dynamically to restore performance:
Copy code
sql
    ADMIN SET FRONTEND CONFIG ("lake_enable_batch_publish_version" = "true");
5. Finalize: Update your Helm
values.yaml
to set it to
true
so the setting persists across future pod restarts. Summary * 4.0.9: Must be
false
(Buggy). * During Upgrade: Keep
false
(Safety). * 4.1.1 (Complete): Set to
true
(Fixed & Recommended). If I previously implied it should be
true
during the upgrade, I misspoke—stability is priority #1 while the binaries are being swapped. Referencesreleasenotes/release-4.1.mdadministration/management/FE_configuration.mddeployment/upgrade.mdknowledge/usage/load/shared_data_batch_ingestion.md Referencesdeployment/upgrade.mdrelease_notes/release-4.0.mdadministration/management/FE_configuration.md
g
@Rocky do you feel pretty good about 4.1.1 helping with some of the errors we are seeing?
r
I feel very good about 4.1.1 specifically solving the root cause of your current headaches. Based on the engineering fixes in the 4.1.1 release, here is why this version is a "silver bullet" for the specific errors you are seeing on 4.0.9: 1. Fix for the "Duplicate Key" Errors (#72237, #71992) The
Already exist: PersistentIndexMemtable insert found duplicate key
error in shared-data mode is almost always caused by the FE and CN nodes losing track of which transaction logs actually "made it" into the storage layer. * The Bug: In 4.0.9, there were race conditions in "combined transaction log" mode where valid logs were incorrectly flagged as "orphans" and discarded. * The Result: The FE thinks a version was written, but the CN never "saw" it. When the next write comes in, the CN tries to index a key that its local Persistent Index says already exists (but the metadata log says is new). * The Fix: 4.1.1 (and 4.0.10) includes specific fixes to the transaction log dispatch logic to ensure these logs are never dropped. 2. Resolution for Delvec Inconsistency (#71049) If you were seeing
delvec inconsistency
after setting
lake_enable_batch_publish_version = true
, 4.1.1 contains the fix for a known issue where compaction and batch-publish would collide. This allows you to safely re-enable the batching optimization in 4.1.1, which will significantly drop your FE CPU usage. 3. Relief for "Publish Tablet Version Latency" A major feature of 4.1 is Intra-tablet Parallelism. * In 4.0.9, publishing a new version to a Primary Key tablet is largely a single-threaded operation per tablet. If you have large tablets or high ingestion rates, the "Publish" phase (visible in your Grafana) becomes a bottleneck. * In 4.1, StarRocks can parallelize the primary key update and compaction pipeline inside a single tablet. This should drastically reduce those "Publish Latency" spikes you are seeing. 4. Safety of 4.1.1 vs 4.1.0 It is important that you go to 4.1.1 and not 4.1.0. The 4.1.0 container image had an unstable load order bug (#71825) that caused CN/BE pods to randomly fail to start in Kubernetes. 4.1.1 was released specifically to fix that. Summary: I am confident that 4.1.1 will stop the metadata/index corruption you are fighting. The "Duplicate Key" error is explicitly addressed by the txn-log race fixes in this branch. Final Upgrade Tip: When you perform the upgrade via Helm, ensure you monitor the
starrocks_be_staros_shard_info_fallback_total
metric in Grafana once you're on 4.1.1. This will help you verify that the new metadata handling is working smoothly without excessive remote lookups. Referencesreleasenotes/release-4.1.mdadministration/management/FE_configuration.mdtable_design/table_types/primary_key_table.mddeployment/helm.mdadministration/management/monitoring/metrics.md
g
@Rocky can you compile a list of bugfixes/improvments/features most applicable for shared-data going from 4.0.9 to 4.1.1?
r
The jump from 4.0.9 to 4.1.1 is a significant upgrade for Shared-Data (Cloud Native) users. It moves you from a version where Primary Key metadata was still being "stabilized" into a version designed for high-scale, parallelized data management. Here is the compiled list of the most applicable changes for your environment: 1. Root Cause Fixes (Your current "Already Exist" errors) * Transaction Log Race Condition Fixed: Fixes a bug where the FE would incorrectly flag legitimate transaction logs as "orphans" and drop them during a heavy dispatch. This was the primary driver of the "Duplicate Key" errors in 4.0.9. * Safe Batch Publishing: Fixes the "delvec inconsistency" issue. You can now safely set
lake_enable_batch_publish_version = true
once you are fully on 4.1.1, which significantly reduces FE CPU load. * Persistent Index Memory Leaks: Several fixes for memory bloat in the Persistent Index during high-frequency updates on CN nodes. 2. High-Scale Shared-Data Features (Primary Key Optimizations) * Large-Capacity Tablet Support (Phase 1): Shared-data tablets can now scale toward 100 GB per tablet (up from the previous ~10 GB recommendation). * Intra-Tablet Parallelism: This is the biggest performance boost. In 4.0.9, a single tablet was a single-threaded bottleneck for ingestion and compaction. 4.1 introduces: * Parallel Compaction: Compaction can now split a single large tablet into segments and process them in parallel. * Parallel Publish: Drastically reduces the "latency" during the transaction commit phase (the "Publish" step in your logs). * Remote-Storage Persistent Index Mapper: The Persistent Index now uses remote-storage mapper files. This makes index recovery much faster after a CN pod restarts or a shard rebalance. 3. Management & Usability Improvements * Range-Based Data Distribution: Supports automatic splitting and merging of tablets. If a specific range of data (e.g., a "hot" day) grows too large, StarRocks can split it automatically to distribute the load across more CNs without you needing to re-bucket the table. * Fast Schema Evolution V2: Second-level DDL for shared-data tables (adding/dropping columns). This is now extended to work with Materialized Views as well. * Inverted Index Support (Beta): You can now use Inverted Indexes in Shared-Data mode to accelerate full-text searches and
WHERE
clauses on non-sort-key columns. 4. Operational & Observability Gains * Container Startup Fix (#71825): 4.1.1 specifically fixes a race condition in the 4.1.0 container image that caused BE/CN processes to fail to start in Kubernetes. * Cache Transparency: New metrics for Cache Hit Ratio and Disk/Memory Quota usage are now exposed in audit logs and Prometheus. This helps you determine if your CN local disks are undersized. * Iceberg Improvements: Shared-data clusters now support DELETE operations on Iceberg tables and better metadata synchronization. Important: The "No-Return" Window While you can downgrade from 4.1.1 to 4.0.9 if needed, do not downgrade to any version below 4.0.6. 4.1 introduces metadata layout changes that versions earlier than 4.0.6 do not understand and could cause metadata corruption if a downgrade is attempted. Summary Recommendation: Upgrading to 4.1.1 is highly recommended for your use case. It specifically targets the Primary Key "bottleneck" and "metadata inconsistency" issues that are common on the 4.0.9 branch. Referencesrelease_notes/release-3.5.mdrelease_notes/release-3.4.mdrelease_notes/release-3.3.md
g
@Rocky if there are running pipes, should I pause them before upgrade?
r
It is strongly recommended to pause your pipes (and any other high-frequency ingestion like Routine Load) before starting the upgrade. While StarRocks supports rolling upgrades, pausing pipes is a critical safety measure for your specific situation for three reasons: 1. Reducing "Noise" and Metadata Pressure You are currently seeing
Already exist
and metadata-related errors on version 4.0.9. If you leave pipes running during a rolling upgrade: * Transactions will likely fail as CN and FE pods restart. * Retries triggered by the pipe might overlap with the version change, potentially triggering more of the very index/metadata inconsistencies you are trying to fix. * By pausing, you ensure that the metadata state is "frozen" while you swap the binaries. 2. Avoiding "Mixed Version" Logic Errors The
Pipe
feature relies on coordination between the FE (which tracks file state) and the CN (which performs the load). During the upgrade, you will have a period where a 4.1.1 FE might be talking to a 4.0.9 CN. Since 4.1.1 introduces significant changes to how shared-data transactions are handled, it is safer not to have active ingestion tasks crossing that version boundary. 3. Clean Recovery If a pipe fails during a node restart, it usually retries automatically. However, in a shared-data environment, if a transaction is "stuck" in a middle state because of an upgrade restart, it's much cleaner to resume from a known paused state than to troubleshoot a failed/partial transaction log created during a version jump. ────────── Recommended Workflow: 1. Suspend all active pipes:
Copy code
sql
-- Do this for each active pipe
ALTER PIPE <pipe_name> SUSPEND;
Verify they are suspended via
SHOW PIPES;
.
2. Perform the Upgrade: * Upgrade CNs (one by one or via Helm rolling update). * Upgrade Follower FEs. * Upgrade Leader FE. 3. Verify Cluster Health: * Check that all nodes are
Alive
and running
4.1.1
. * Ensure your
lake_enable_batch_publish_version
flag is set correctly (start with
false
and move to
true
once stable). 4. Resume Pipes: Resume them one at a time to monitor for any errors:
Copy code
sql
ALTER PIPE <pipe_name> RESUME;
Pro-Tip: If you have a large number of pipes, you can generate the suspend/resume commands using the `information_schema`:
Copy code
sql
-- Generate Suspend commands
SELECT CONCAT('ALTER PIPE ', database_name, '.', pipe_name, ' SUSPEND;') 
FROM information_schema.pipes WHERE state = 'RUNNING';
Referencessql-reference/sql-statements/loading_unloading/pipe/SUSPEND_or_RESUME_PIPE.mddeployment/upgrade.mdloading/hdfs_load.mdloading/s3.md Referencesdeployment/upgrade.mdrelease_notes/release-3.2.mdloading/hdfs_load.md
g
@Rocky upgrade went smoothly except getting
Copy code
"5064 (42000): Getting analyzing error. Detail message: Class 'udfs.LatLonToH3UDF' not found in object_file :file:///opt/starrocks/udf-jars/starrocks-geo-udf-all-1.1.jar,udfs.LatLonToH3UDF.",
did something change with how udfs are loaded
r
It looks like your UDF is failing because the local file path used during the
CREATE FUNCTION
statement is likely missing or inaccessible on the new 4.1.1 pods. In a Kubernetes or shared-data environment, using
file:///
for UDFs is risky because when you upgrade (which replaces the pods), the local filesystem of the new pods is fresh and won't contain the JAR file unless you explicitly mounted it via a Persistent Volume or
hostPath
. 1. The Immediate Cause: Missing JAR or Permissions The error
Class '...' not found in object_file
often occurs when StarRocks fails to correctly open or read the JAR at the specified path on the BE/CN nodes. * Check existence: Exec into one of your new CN/BE pods and verify if
/opt/starrocks/udf-jars/starrocks-geo-udf-all-1.1.jar
actually exists. * Permissions: Ensure the
starrocks
user inside the container has read access to that file. 2. The "Correct" Fix for Shared-Data/K8s The recommended way to handle UDFs in a distributed, cloud-native environment is to host the JAR on an HTTP/HTTPS server (or S3/Minio). This ensures that whenever a new CN pod scales up or restarts, it can automatically download the JAR. Recommendation: 1. Upload the JAR to an internal S3 bucket or a simple HTTP server accessible by the cluster. 2. Drop and recreate the function using the HTTP URL:
Copy code
sql
    DROP FUNCTION LatLonToH3UDF(...); -- matching your signature

    CREATE FUNCTION LatLonToH3UDF(DOUBLE, DOUBLE, INT)
    RETURNS STRING
    PROPERTIES (
        "symbol" = "udfs.LatLonToH3UDF",
        "type" = "StarrocksJar",
        "file" = "<http://your-internal-server/starrocks-geo-udf-all-1.1.jar>"
    );
3. Check for JDK 17 Requirements StarRocks 4.x (built on the 3.x line) requires JDK 17 for Java UDFs. If your UDF was compiled with an older version or if the new BE images are missing specific JVM flags, it may fail to load. Ensure your
be.conf
(or the BE environment variables in Helm) includes these flags in
JAVA_OPTS
to allow the UDF classloader to work:
Copy code
bash
--add-opens=java.base/java.nio=ALL-UNNAMED 
--add-opens=java.base/sun.nio.ch=ALL-UNNAMED
4. Why did it work before? If you weren't using a Persistent Volume, you might have manually copied the JAR into the 4.0.9 pods. When you upgraded to 4.1.1, the Helm chart deleted the old pods and created new ones, wiping out any files you manually placed in
/opt/starrocks/
. Next Steps: * Verify the JAR exists on the pod. * If you must use local files, you'll need to update your Helm
values.yaml
to mount a volume containing the JARs. * Otherwise, switching the
file
property to an HTTP URL is the most stable fix for 4.1.1. Referencessql-reference/sql-functions/JAVA_UDF.mdadministration/management/FE_configuration.mdrelease_notes/release-3.5.mddeployment/helm.mdsql-reference/sql-statements/loading_unloading/pipe/CREATE_PIPE.md Referencessql-reference/sql-functions/hive_bitmap_udf.mdsql-reference/sql-functions/Python_UDF.mdsql-reference/sql-functions/JAVA_UDF.mdrelease_notes/release-4.0.mdrelease_notes/release-3.5.mdrelease_notes/release-2.2.mdrelease_notes/release-3.4.md
g
@Rocky do i need to add these for CNs as well
Copy code
bash
--add-opens=java.base/java.nio=ALL-UNNAMED 
--add-opens=java.base/sun.nio.ch=ALL-UNNAMED
r
Yes, you absolutely need to add these flags to your CN nodes (Compute Nodes) as well. In StarRocks Shared-Data mode, the CN nodes are responsible for the actual execution of queries, including the execution of Java UDFs. Because StarRocks 4.1 runs on JDK 17, it strictly enforces module boundaries. Without these
add-opens
flags, the JVM will block the StarRocks C++ process (via JNI) from accessing the internal Java memory buffers required to pass data between the database and your UDF. Why this is required for CNs: * Role Identity: In Shared-Data clusters, CNs perform the exact same computation role that BEs do in Shared-Nothing clusters. Any requirement for "BE configuration" regarding execution or UDFs applies directly to CNs. * Data Passing: StarRocks uses specific Java internal APIs (
java.nio
) to move data efficiently between the C++ engine and the Java VM. JDK 17 "strongly encapsulates" these APIs by default. How to add them to CNs: If you are running in Kubernetes (Helm), you should add these to the
envVars
or
config
section of your CN spec in the `values.yaml`:
Copy code
yaml
compute:
  envVars:
    - name: JAVA_OPTS
      value: "-Xmx8G --add-opens=java.base/java.nio=ALL-UNNAMED --add-opens=java.base/sun.nio.ch=ALL-UNNAMED"
If you are running manually (on VMs), add them to your
cn/conf/cn.conf
(which is often just a renamed
be.conf
):
Copy code
bash
# Add to the existing JAVA_OPTS line
JAVA_OPTS="... --add-opens=java.base/java.nio=ALL-UNNAMED --add-opens=java.base/sun.nio.ch=ALL-UNNAMED"
Summary of required flags for 4.1.x: 1. For Java UDFs: *
--add-opens=java.base/java.nio=ALL-UNNAMED
*
--add-opens=java.base/sun.nio.ch=ALL-UNNAMED
2. For External Catalogs (e.g., Iceberg/Hive): *
--add-opens=java.base/java.util=ALL-UNNAMED
(Also highly recommended to avoid
InaccessibleObjectException
). Note: After adding these flags, you must restart the CN processes for the changes to take effect. Referencessql-reference/sql-functions/JAVA_UDF.mdadministration/management/FE_configuration.mdrelease_notes/release-3.5.mddeployment/helm.mdsql-reference/sql-statements/loading_unloading/pipe/CREATE_PIPE.md Referencessql-reference/sql-functions/JAVA_UDF.md
g
@Rocky why did it work with 4.0.9 and not now?
r
The reason your UDF worked in 4.0.9 but is failing in 4.1.1 is likely due to a combination of how Kubernetes handles pod upgrades and changes in the StarRocks engine's strictness regarding Java environments. Here are the three most likely reasons: 1. Pod Recreation (The "Ephemeral Storage" Trap) This is the most common reason in Kubernetes environments. * In 4.0.9: You likely copied the JAR file into the
/opt/starrocks/udf-jars/
directory of the running pods manually or via a startup script that wasn't persisted. * The Upgrade: When you upgraded to 4.1.1, the Helm chart (or operator) deleted the old 4.0.9 pods and created brand new 4.1.1 pods. * The Result: Since the local filesystem of a pod is ephemeral, the
/opt/starrocks/udf-jars/
folder in the new pods is empty. Because the
CREATE FUNCTION
statement points to a local file path (
file:///...
), the CN nodes are looking for a file that no longer exists on their new disks. 2. JDK 17 & JNI Strictness StarRocks 4.x (and the 3.5+ line it is based on) requires JDK 17. * Version 4.1.x introduced more rigorous error checking for Java JNI calls. In older versions, if the JVM had a minor initialization issue or a "soft" failure due to missing
JAVA_OPTS
, the engine might have silently retried or bypassed the check in a way that appeared to work. * Version 4.1.1 now explicitly checks for exceptions during JNI object creation. If your
JAVA_OPTS
(the
--add-opens
flags) are missing, the JVM throws an
InaccessibleObjectException
. In 4.1.1, this now correctly bubbles up as an "Analyzing error" or "Class not found" because the classloader failed to initialize the environment properly. 3. Changes in UDF Loading Logic Release notes for the 4.1.x line (specifically around 4.1.1 and 4.0.10) indicate that Java UDF/UDAF instances are now loaded once per query and reused across pipeline instances to improve performance. * In 4.0.9, the loading happened more frequently/differently. * In 4.1.1, the new centralized loading logic is more sensitive to environment issues. If the JAR isn't exactly where it's expected or if the JVM permissions are missing, the query will fail immediately during the "Analyzing" phase before the actual execution starts. ────────── How to verify and fix: 1. Confirm the file is missing:
kubectl exec -it <cn-pod-name> -- ls -l /opt/starrocks/udf-jars/
If it’s empty, you've found the issue. 2. The Permanent Fix: Move the JAR to a remote location (S3, Minio, or an HTTP server) and update the function to use an
http://
or
s3://
URL. This makes the UDF "pod-restart proof." 3. Add the Flags: Ensure those
--add-opens
flags are in your
CN
environment variables. Even if you get the file back, the UDF will likely crash or return errors without them on JDK 17. Referencessql-reference/sql-functions/JAVA_UDF.mdrelease_notes/release-4.1.mdadministration/management/FE_configuration.mdrelease_notes/release-3.5.mddeployment/helm.md Referencessql-reference/sql-functions/JAVA_UDF.mdrelease_notes/release-4.1.mdrelease_notes/release-3.5.mdrelease_notes/release-4.0.mdadministration/management/FE_configuration.md Referencessql-reference/sql-functions/JAVA_UDF.md
g
@Rocky does the fe need those java opts too?
r
Yes, it is highly recommended to add these
JAVA_OPTS
to your FE (Front End) as well. While the BE/CN does the heavy lifting for UDF execution, the FE is responsible for the Analysis phase. During this phase, the FE attempts to load the JAR metadata to verify that the
symbol
(your class name) and the function signature are valid. If the FE is running on JDK 17 without these flags, it can encounter the same "strong encapsulation" errors when trying to inspect the JAR or initialize the classloader, leading to the "Analyzing error" you are seeing. 1. Update
fe.conf
Add these to your
JAVA_OPTS
in `fe.conf`:
Copy code
bash
JAVA_OPTS="-Xmx8192m --add-opens=java.base/java.nio=ALL-UNNAMED --add-opens=java.base/sun.nio.ch=ALL-UNNAMED"
(Note: If you are using External Catalogs like Iceberg or Hive, you should also add
--add-opens=java.base/java.util=ALL-UNNAMED
to the FE).
2. The "Analyzing Error" and
file:///
The specific error
Class ... not found in object_file :file:///...
usually points to one of two issues on the FE side: * Locality: When you use
file:///
, the JAR file must exist on the FE pod at that exact path. If you only put the JAR on the CN/BE pods, the FE will fail during the analysis/planning stage because it can't find the file to validate your UDF. * Permissions: The FE process must have read permissions for that directory and file. Recommendation: Switch to HTTP To avoid having to manually sync the JAR file across every single FE, CN, and BE pod (and ensuring it survives pod restarts), you should host the JAR on an internal HTTP/S3 server. When you use an HTTP URL, the FE and CNs will automatically download the JAR into their local cache when needed, making the cluster much easier to manage.
Copy code
sql
-- Recreate using a URL instead of a local path
CREATE FUNCTION LatLonToH3UDF(...) 
RETURNS STRING
PROPERTIES (
    "symbol" = "udfs.LatLonToH3UDF", 
    "type" = "StarrocksJar",
    "file" = "<http://your-internal-repo/starrocks-geo-udf-all-1.1.jar>"
);
Summary of Actions 1. Add the
add-opens
flags to FE
JAVA_OPTS
to ensure the JVM can handle the UDF metadata analysis. 2. Verify the JAR exists on the FE pod if you continue using
file:///
. 3. Restart the FE after modifying
fe.conf
. Referencessql-reference/sql-functions/JAVA_UDF.mdadministration/management/FE_configuration.mdrelease_notes/release-3.5.mddeployment/helm.md Referencessql-reference/sql-functions/JAVA_UDF.mdadministration/management/FE_configuration.mdrelease_notes/release-3.5.md Referencessql-reference/sql-functions/JAVA_UDF.mdadministration/management/FE_configuration.mdadministration/management/BE_configuration.md
g
@Rocky the files are getting placed on the pods correctly, I don't want to change that now. what should the process of updating the opts for both FE and CN look like?
r
Since
JAVA_OPTS
is a static JVM configuration, it cannot be updated dynamically via SQL. You must modify the configuration files and restart the processes. To maintain cluster availability, you should follow a rolling restart process. Scenario A: Manual Deployment (On VMs) If you are managing the processes directly on Linux servers: 1. Update the Configuration Files On every FE and CN node, locate the configuration files and append the required flags to the
JAVA_OPTS
line. * FE:
fe/conf/fe.conf
* CN:
cn/conf/cn.conf
(or
be.conf
if that is what you are using)
Copy code
bash
# Example line in fe.conf/cn.conf
JAVA_OPTS="-Xmx... --add-opens=java.base/java.nio=ALL-UNNAMED --add-opens=java.base/sun.nio.ch=ALL-UNNAMED"
2. Rolling Restart Sequence Restart nodes one by one to ensure the cluster remains online. For CN Nodes: 1. Stop Gracefully: Run
./bin/stop_cn.sh --graceful
(or
-g
). This allows the CN to finish in-flight queries before shutting down. 2. Start: Run
./bin/start_cn.sh --daemon
. 3. Verify: Check the logs or run
SHOW COMPUTE NODES;
to ensure it is
Alive
. 4. Repeat for the next CN. For FE Nodes: 1. Start with Followers: Restart the non-leader FEs first. 2. Stop Gracefully: Run
./bin/stop_fe.sh -g
. 3. Start: Run
./bin/start_fe.sh --daemon
. 4. Restart Leader Last: When you stop the Leader FE, a new Leader will be elected. The cluster will have a few seconds of "write-unavailability" during the election, but reads will continue. ────────── Scenario B: Kubernetes Deployment (Helm/Operator) If you are using the StarRocks Kubernetes Operator or Helm chart, the process is much simpler as Kubernetes handles the orchestration. 1. Update your
values.yaml
Add the flags to the
envVars
section for both the FE and CN components.
Copy code
yaml
fe:
  envVars:
    - name: JAVA_OPTS
      value: "-Xmx8G --add-opens=java.base/java.nio=ALL-UNNAMED --add-opens=java.base/sun.nio.ch=ALL-UNNAMED"

compute: # or 'cn' depending on your chart version
  envVars:
    - name: JAVA_OPTS
      value: "-Xmx8G --add-opens=java.base/java.nio=ALL-UNNAMED --add-opens=java.base/sun.nio.ch=ALL-UNNAMED"
2. Apply the Change Run the Helm upgrade command:
Copy code
bash
helm upgrade <release-name> starrocks/starrocks-stack -f values.yaml
3. Automatic Rolling Update Kubernetes will detect the environment variable change and perform a Rolling Update: * It will terminate one pod at a time. * It will wait for the new pod to be
Ready
(Health Check pass) before moving to the next. * Since your JAR files are "placed on the pods correctly," ensure your placement method (like an
initContainer
or a mounted
HostPath
) is still active so the new pods get the files upon startup. How to verify the fix After the restart, you can verify the JVM is running with the new flags by running this command inside the pod/server:
Copy code
bash
ps aux | grep java
Look for the
--add-opens
flags in the process arguments. Once verified, your UDF should no longer throw the "Analyzing error" or "InaccessibleObjectException." Referencesadministration/management/graceful_exit.mddeployment/upgrade.mdadministration/management/FE_configuration.mddeployment/helm.md Referencesadministration/management/graceful_exit.mddeployment/upgrade.mdadministration/management/FE_configuration.md Referencesadministration/management/graceful_exit.md
g
@Rocky I already have this for my FE JAVA_OPTS do i just add to it?
JAVA_OPTS="-Dlog4j2.formatMsgNoLookups=true -Xms16g -Xmx16g -XX:MetaspaceSize=512m -XX:MaxMetaspaceSize=1g -XX:+UseG1GC -Xlog:gc*:${LOG_DIR}/fe.gc.log.$DATE:time"
r
Yes, you should append the new flags to your existing
JAVA_OPTS
. You do not need to replace anything, as your current flags (G1GC, Metaspace, and log4j protection) are all still valid and recommended for StarRocks. The Combined FE
JAVA_OPTS
You can copy and paste this combined line into your `fe/conf/fe.conf`:
Copy code
bash
JAVA_OPTS="-Dlog4j2.formatMsgNoLookups=true -Xms16g -Xmx16g -XX:MetaspaceSize=512m -XX:MaxMetaspaceSize=1g -XX:+UseG1GC -Xlog:gc*:${LOG_DIR}/fe.gc.log.$DATE:time --add-opens=java.base/java.nio=ALL-UNNAMED --add-opens=java.base/sun.nio.ch=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED"
Why these three specifically? 1.
java.nio
&
<http://sun.nio.ch|sun.nio.ch>
: These are strictly required for Java UDFs. They allow the StarRocks engine to use direct memory buffers for passing data between the C++ engine and the JVM. Without these, you get the "InaccessibleObjectException" during the Analyzing phase. 2.
java.util
: While the docs primarily mention this for External Catalogs (Hive/Iceberg), it is highly recommended to include it on the FE for UDFs as well. Many Java libraries used inside UDFs (like H3, Jackson, or Guava) use reflection on
java.util
structures which JDK 17 blocks by default. What about the CN? For your CN (Compute Nodes), you should use a similar approach. Since CNs usually don't need as much Heap memory as the FE (because they use off-heap memory for processing), a common CN
JAVA_OPTS
looks like this:
Copy code
bash
# Example for CN (adjust -Xmx based on your pod memory limit)
JAVA_OPTS="-Xms4g -Xmx4g --add-opens=java.base/java.nio=ALL-UNNAMED --add-opens=java.base/sun.nio.ch=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED"
Verification Step After you update the files and restart the pods, run this command to make sure the flags actually took effect:
Copy code
bash
ps aux | grep java
If you see the
--add-opens
strings in the output of the running FE and CN processes, your UDFs should start working immediately. Referencessql-reference/sql-functions/JAVA_UDF.mdrelease_notes/release-3.5.mdadministration/management/FE_configuration.mdfaq/Others.md Referencessql-reference/sql-functions/JAVA_UDF.mdrelease_notes/release-3.5.mdadministration/management/FE_configuration.md Referencessql-reference/sql-functions/JAVA_UDF.mdadministration/management/BE_configuration.mdadministration/management/FE_configuration.mdfaq/Others.mdknowledge/trouble_shooting/fe_memory_problems.md
g
@Rocky i don't currently have a JAVA_OPTS for cns, ok to just add the add-in bits and not mess with memory?
r
It is technically "okay" to only add the
--add-opens
bits, but there is a catch: StarRocks configuration usually treats
JAVA_OPTS
as an override.
If you define
JAVA_OPTS
in
cn.conf
, the startup script will likely use only what you provide and ignore its internal defaults. If those defaults included a memory limit (like
-Xmx
), you might unintentionally change how much memory the JVM uses. Recommendation: Set a small Heap for CNs Unlike the FE (which needs 16GB+), the CN doesn't use the JVM for its main engine; it only uses it for "helper" tasks like Java UDFs and reading certain external formats (Hudi/Iceberg). Because you don't want to mess with memory too much, I recommend adding a safe, conservative heap size along with your required flags. This ensures the JVM has enough room to run your H3 UDF without competing with the main C++ process for all the system's RAM. Add this to your
cn.conf
(or
be.conf
):
Copy code
bash
JAVA_OPTS="-Xms1g -Xmx1g --add-opens=java.base/java.nio=ALL-UNNAMED --add-opens=java.base/sun.nio.ch=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED"
Why
-Xmx1g
?
* Safety: 1GB is usually plenty for running UDFs. * Predictability: CN nodes are designed to use most of their RAM for the C++ memory pool (tracked by
mem_limit
). By capping the JVM at 1GB, you ensure it doesn't grow unexpectedly and cause the pod to be OOM-killed (Out of Memory) by the OS or Kubernetes. * Defaults: If you provide no memory flags, the JVM defaults to using 1/4 of the physical memory. On a 64GB machine, that’s 16GB—which is likely much more than you want the JVM to take away from the main StarRocks engine. Summary 1. FE: Use your existing 16GB string + the three
--add-opens
flags. 2. CN: Add the line above (
-Xmx1g
+ the three flags). 3. Restart: Perform the rolling restart as discussed. Referencessql-reference/sql-functions/JAVA_UDF.mdrelease_notes/release-3.5.mdadministration/management/BE_configuration.mdadministration/management/FE_configuration.md Referencessql-reference/sql-functions/JAVA_UDF.mdrelease_notes/release-3.5.mdadministration/management/BE_configuration.mdadministration/management/FE_configuration.md Referencessql-reference/sql-functions/JAVA_UDF.mddeployment/environment_configurations.mdadministration/management/FE_configuration.mdadministration/management/BE_configuration.mddeployment/deploy_manually.mdsql-reference/System_variable.md
g
@Rocky i made the changes you suggested but still
Copy code
"5064 (42000): Getting analyzing error. Detail message: Class 'udfs.LatLonToH3UDF' not found in object_file :file:///opt/starrocks/udf-jars/starrocks-geo-udf-all-1.1.jar,udfs.LatLonToH3UDF.",
r
Sorry, I encountered an error while processing your request: 400 INVALID_ARGUMENT. {'error': {'code': 400, 'message': 'The answer candidate length is too long with 14250 tokens, which exceeds the maximum token limit of 8192.', 'status': 'INVALID_ARGUMENT'}}
g
@Rocky can i still use the
"file" = "file:///..."
method of registering UDFs in 4.1.1 or was that depreciated?
r
The short answer is: The
file:///
method is not officially deprecated, but it is strongly discouraged in distributed environments
, and the behavior you are seeing is exactly why. In StarRocks (including version 3.x and 4.x), the recommended way to register a UDF is via an HTTP/HTTPS URL. Why
file:///
is likely causing your error
When you use
file:///
, StarRocks expects that every single FE and every single CN/BE node has that exact JAR file at that exact same local path (
/opt/starrocks/udf-jars/...
). The error
"Class 'udfs.LatLonToH3UDF' not found in object_file..."
typically happens for one of two reasons: 1. Missing File on Worker Nodes: The CN node executing the query doesn't have the JAR file at that path. 2. Symbol Mismatch: The JAR exists, but the class name provided in the
symbol
property doesn't match the actual package/class structure inside the JAR. The Recommended Fix: Use an HTTP Server Instead of trying to sync files across all your pods manually, the standard approach is to host the JAR on a simple HTTP server (like an internal Nginx, an S3 bucket with a public/presigned URL, or even a simple Python
http.server
running in a management pod). Update your registration to this format:
Copy code
sql
CREATE [GLOBAL] FUNCTION h3_lat_lon_to_cell(DOUBLE, DOUBLE, INT)
RETURNS BIGINT
PROPERTIES (
    "symbol" = "udfs.LatLonToH3UDF", 
    "type" = "StarrocksJar",
    "file" = "<http://your-internal-repo/starrocks-geo-udf-all-1.1.jar>"
);
If you must use
file:///
If you are determined to use the local path (e.g., you are using a Shared Volume in Kubernetes like an NFS/PVC mounted to all pods): 1. Verify the Class Name: Run this command to ensure the class
udfs.LatLonToH3UDF
is actually inside the JAR:
Copy code
bash
    jar -tf /opt/starrocks/udf-jars/starrocks-geo-udf-all-1.1.jar | grep LatLonToH3UDF
The output should look like
udfs/LatLonToH3UDF.class
. If it looks like
com/example/udfs/LatLonToH3UDF.class
, your symbol must be
com.example.udfs.LatLonToH3UDF
. 2. Check Permissions: Ensure the
starrocks
user in your container has read permissions for both the directory and the JAR file. 3. Check all CNs: Log into every CN pod and verify the file exists. If even one pod is missing it, the query will fail whenever it happens to be scheduled on that node. Pro-tip: Since you are on a very recent version (4.x), using an HTTP URL is much safer because StarRocks will automatically download the JAR and cache it locally on each node, ensuring consistency across the cluster, ensuring consistency. Referencessql-reference/sql-functions/JAVA_UDF.mdsql-reference/sql-statements/Function/CREATE_FUNCTION.mdrelease_notes/release-4.0.md Referencessql-reference/sql-functions/JAVA_UDF.mdsql-reference/sql-statements/Function/CREATE_FUNCTION.mdrelease_notes/release-4.0.mdrelease_notes/release-2.1.md -index) • administration/management/BE_configuration.mdadministration/management/FE_configuration.mddeployment/environment_configurations.mddeployment/deploy_manually.mdsql-reference/System_variable.md
g
@Rocky this seems fine yes?
Copy code
starrocks@kube-starrocks-cn-3:/opt/starrocks/udf-jars$ ls -la
total 1396
drwxrwsrwx 2 root      starrocks    4096 Jun 10 18:34 .
drwxr-xr-x 1 starrocks starrocks    4096 Jun 10 18:34 ..
-r--r--r-- 1 starrocks starrocks 1419104 Jun 10 18:34 starrocks-geo-udf-all-1.1.jar
starrocks@kube-starrocks-cn-3:/opt/starrocks/udf-jars$ jar -tf starrocks-geo-udf-all-1.1.jar | grep LatLonToH3UDF
udfs/LatLonToH3UDF.class
r
The JAR file and class look correct on your CN node, but the error persists because of how StarRocks handles UDF registration. The Problem: The FE also needs the JAR When you use
file:///
, StarRocks requires the JAR file to be present at that exact same path on every FE node and every CN node in the cluster. The "Analyzing error" you are seeing is likely coming from the FE (Frontend). Before the query even reaches the CN, the FE must load the JAR to inspect the class, verify the method signature (the types of arguments and return value), and validate the symbol. If the FE cannot find the file on its own local disk, it throws the "Class not found" error. How to verify Run this command against your FE pod(s):
Copy code
bash
kubectl exec -it <your-fe-pod-name> -- ls -la /opt/starrocks/udf-jars/starrocks-geo-udf-all-1.1.jar
If this returns "No such file or directory," that is your culprit. Solutions 1. The "Correct" Way (HTTP) Upload the JAR to a location accessible via HTTP (like an S3 bucket, Artifactory, or even a simple Nginx pod).
Copy code
sql
CREATE FUNCTION ... 
PROPERTIES (
    "symbol" = "udfs.LatLonToH3UDF", 
    "type" = "StarrocksJar",
    "file" = "<http://my-internal-server/udfs/starrocks-geo-udf-all-1.1.jar>"
);
* Why: When you use an HTTP URL, the FE downloads it once to analyze it, and the CNs download and cache it locally when they need to run it. You don't have to manually sync files to any pods. 2. The "Manual" Way (If you must stay with
file:///
)
If you cannot use HTTP, you must: 1. Copy the JAR into every FE pod at
/opt/starrocks/udf-jars/
. 2. Ensure the JAR is in every CN pod (not just node 3). 3. Ensure the
starrocks
user has read permissions on all nodes. Summary The
file:///
method still works in 4.1.1, but it is fragile because it assumes a perfectly mirrored filesystem across all pods. Since you are in Kubernetes, unless you are using a Shared Persistent Volume (RWX) mounted to all pods at that path,
file:///
will almost always fail on the FE or a different CN node. Referencessql-reference/sql-functions/JAVA_UDF.mdsql-reference/sql-statements/Function/CREATE_FUNCTION.mdadministration/management/FE_configuration.mddeployment/deploy_manually.md Referencessql-reference/sql-functions/JAVA_UDF.mdsql-reference/sql-statements/Function/CREATE_FUNCTION.mdadministration/management/FE_configuration.mddeployment/deploy_manually.md Referencessql-reference/sql-functions/JAVA_UDF.mdsql-reference/sql-statements/Function/CREATE_FUNCTION.mdadministration/management/FE_configuration.mdadministration/management/BE_configuration.mddeployment/deploy_manually.mdsql-reference/System_variable.mdfaq/Others.mdknowledge/trouble_shooting/fe_memory_problems.md
g
hmm this doesn't seem right @Rocky
Copy code
starrocks@kube-starrocks-fe-2:/opt/starrocks/udf-jars$ ls -la
total 12
drwxrwsrwx 2 root      starrocks 4096 Jun 10 18:34 .
drwxr-xr-x 1 starrocks starrocks 4096 Jun 10 18:34 ..
-r--r--r-- 1 starrocks starrocks  297 Jun 10 18:34 starrocks-geo-udf-all-1.1.jar
starrocks@kube-starrocks-fe-2:/opt/starrocks/udf-jars$ jar -tf starrocks-geo-udf-all-1.1.jar | grep LatLonToH3UDF
java.util.zip.ZipException: zip END header not found
        at java.base/java.util.zip.ZipFile$Source.findEND(ZipFile.java:1637)
        at java.base/java.util.zip.ZipFile$Source.initCEN(ZipFile.java:1645)
        at java.base/java.util.zip.ZipFile$Source.<init>(ZipFile.java:1483)
        at java.base/java.util.zip.ZipFile$Source.get(ZipFile.java:1445)
        at java.base/java.util.zip.ZipFile$CleanableResource.<init>(ZipFile.java:717)
        at java.base/java.util.zip.ZipFile.<init>(ZipFile.java:251)
        at java.base/java.util.zip.ZipFile.<init>(ZipFile.java:180)
        at java.base/java.util.zip.ZipFile.<init>(ZipFile.java:151)
        at jdk.jartool/sun.tools.jar.Main.list(Main.java:1503)
        at jdk.jartool/sun.tools.jar.Main.run(Main.java:368)
        at jdk.jartool/sun.tools.jar.Main.main(Main.java:1681)
r
You've found the smoking gun. Your JAR file on the FE is definitely corrupted or incomplete. Notice the size difference: * On your CN node:
1,419,104
bytes (~1.4 MB). * On your FE node:
297
bytes. A 297-byte file is not a valid Java JAR (which is why
jar -tf
threw the
ZipException
). In Kubernetes environments, this specific behavior usually happens for one of two reasons: 1. The ConfigMap Size Limit (Most Likely) If you are deploying this JAR via a Kubernetes ConfigMap, you have hit the 1MB limit. Kubernetes ConfigMaps and Secrets have a strict 1MB size limit. When you try to put a 1.4MB JAR into a ConfigMap, it either fails to apply or gets truncated/corrupted, resulting in that tiny file you see. 2. Failed
kubectl cp
If you used
kubectl cp
to move the file, it may have disconnected mid-transfer, leaving a partial file. How to fix this Option A: Use a real HTTP source (Highly Recommended) Since you are in Kubernetes, don't try to sync files manually. It's the "anti-pattern" for distributed databases. 1. Upload the JAR to any internal HTTP server, S3 bucket, or MinIO. 2. Register the UDF using the URL:
Copy code
sql
    CREATE FUNCTION ... PROPERTIES ("file" = "<http://minio.svc.cluster.local/jars/starrocks-geo-udf-all-1.1.jar>", ...);
StarRocks FE and CNs will download the file themselves, bypassing the 1MB K8s limit. Option B: Use a Persistent Volume (Shared Storage) If you have a Shared Volume (like EFS, Longhorn, or any NFS-backed PVC) mounted to both your FEs and CNs at `/opt/starrocks/udf-jars`: 1. Place the JAR file once in that shared volume. 2. Because it's the same physical storage, all pods will see the full 1.4MB file. Option C: Manual
kubectl cp
(Quick Fix)
If you just want to test right now, manually copy the file from your local machine to the FE pod:
Copy code
bash
kubectl cp starrocks-geo-udf-all-1.1.jar <fe-pod-name>:/opt/starrocks/udf-jars/starrocks-geo-udf-all-1.1.jar
Then run the
ls -la
command again on the FE to ensure the size is exactly 1,419,104 bytes before running the
CREATE FUNCTION
statement. Summary: The FE is the "brain" that validates the UDF. If the FE's copy of the JAR is broken (even if the CN's copy is fine), the
CREATE FUNCTION
command will fail every time.
g
@Rocky can i re-deploy the fe's and see if it's fixed?
r
The short answer is no, re-deploying the FE will likely not fix it and might actually make it worse, depending on how you put the file there. Here is why re-deploying won't solve the "297-byte JAR" problem: 1. If you used
kubectl cp
If you manually copied the JAR into the FE pod using
kubectl cp
, re-deploying the pod will delete the file entirely. Kubernetes pods have ephemeral filesystems; any manual changes made inside a running pod are wiped out when the pod restarts or re-deploys. You would end up with a "File not found" error instead of a "Class not found" error. 2. If you used a ConfigMap or Secret If you are mounting this JAR via a Kubernetes ConfigMap or Secret, re-deploying will simply mount the same 297-byte corrupted file again. * The Culprit: Kubernetes ConfigMaps have a strict 1MB size limit. * The Symptom: When you try to store a 1.4MB JAR in a ConfigMap, Kubernetes often truncates the data or fails to encode it properly, resulting in a tiny, broken file (like your 297-byte result). 3. Why the FE is the "Gatekeeper" Even if the JAR is perfect on your CN nodes, the
CREATE FUNCTION
command must run on the FE first. The FE acts as the gatekeeper: it opens the JAR, validates the Java class exists, checks the method signatures, and calculates a checksum. Because your FE has a corrupted 297-byte file, it can't "unzip" the JAR to see the class, so it fails before the CN ever gets a chance to try. ────────── The Recommended Path Forward Step 1: Abandon
file:///
for Kubernetes
The
file:///
method is meant for legacy bare-metal installs. In Kubernetes, the "StarRocks way" is to use an HTTP URL. 1. Host your JAR on a simple internal service (e.g., a MinIO bucket, an Nginx pod, or even a public GitHub release link). 2. Run your SQL like this:
Copy code
sql
    CREATE FUNCTION h3_lat_lon_to_cell(DOUBLE, DOUBLE, INT)
    RETURNS BIGINT
    PROPERTIES (
        "symbol" = "udfs.LatLonToH3UDF",
        "type" = "StarrocksJar",
        "file" = "<http://your-file-server/starrocks-geo-udf-all-1.1.jar>"
    );
* Result: The FE will download the full JAR into its own internal cache, and the CNs will do the same when they need it. No manual syncing or K8s size limits required. Step 2: If you must use local files (The "PVC" Way) If security policies prevent HTTP, you must use a Persistent Volume (PV) with
ReadWriteMany
(RWX) access: 1. Mount the same PVC to
/opt/starrocks/udf-jars/
on both your FE and CN pod templates. 2. Place the JAR into that volume once. 3. Because it's a real disk volume, it won't hit the 1MB ConfigMap limit and it won't disappear when you re-deploy. Summary: Your current error is caused by a corrupted JAR on the FE. Re-deploying won't fix a truncated ConfigMap or a manual file copy. Switch to an HTTP URL to resolve this instantly. Referencesadministration/management/BE_configuration.mdsql-reference/sql-functions/JAVA_UDF.mdadministration/management/FE_configuration.mdsql-reference/sql-functions/Python_UDF.md
g
@Rocky after bumping to 4.1.1 from 4.0.9, things were going smoothly until
Copy code
Fail to publish partition 2822666 error Fail to publish version for tablets:[[2822672, 2822668, 2822670]], error msg: prepare_primary_index: load primary index failed: Not found: load_segments failed tablet:2822670 rowset:19 segid:0: starlet err Object https://<storage_account>/dataops-k8-blob/starrocks/c06faf1f-a109-4cf6-a569-f20a4df260be/db49953/2618536/2822666/data/0000000000216206_1476812a-dfaa-4f78-aa2a-538c72d13ee1.dat does not exist
be/src/storage/lake/rowset.cpp:481 load_segments(&segments, false), host: kube-starrocks-cn-0.kube-starrocks-cn-search.kube-starrocks.svc.cluster.local
this happened recently so it's a good time to debug. I need to figure this out if we plan to continue using starrocks.
r
This is a serious data consistency error in StarRocks' shared-data (Cloud-Native) mode. Specifically, your Primary Key table has become unavailable because its metadata references a segment file (
.dat
) that no longer exists in your Azure Blob storage. The error
prepare_primary_index: load primary index failed
happens because, in Primary Key tables, the system must load the Primary Index from existing rowsets to apply new updates. If a single segment is missing, the index cannot be built, and the "publish" phase of your transaction fails. Why this happened In shared-data clusters, this typically occurs due to: 1. Compaction/GC Race: A bug in the Garbage Collection (GC) logic might have cleaned up a segment that was still being referenced by a tablet version. 2. Metadata Inconsistency: During your upgrade from 4.0.9 to 4.1.1, a Leader FE switch or a compaction task might have committed metadata that pointed to a file that wasn't fully persisted or was prematurely deleted. 3. Manual Deletion: Accidental manual cleanup in the Azure storage account. How to fix it (StarRocks 4.1.1) Since you are on version 4.1.1, you can use the new Cloud-Native Table Repair feature. This mechanism scans historical metadata versions to find the most recent "healthy" state where all files still exist and rolls the affected tablets back to that version. 1. Identify the affected Partition Find the partition name for the ID mentioned in your error (
2822666
):
Copy code
sql
SELECT TABLE_NAME, PARTITION_NAME 
FROM information_schema.partitions_meta 
WHERE PARTITION_ID = 2822666;
2. Run the Repair Command Execute the following to roll back the corrupted tablets to their last known good version:
Copy code
sql
ADMIN REPAIR TABLE <your_table_name> PARTITION (<your_partition_name>);
* Strict Consistency (Default): This will find the latest version that is valid for all tablets in the partition and roll them all back to that point. * Maximum Availability: If you want to keep as much data as possible even if tablets end up at slightly different versions, use:
Copy code
sql
    ADMIN REPAIR TABLE <your_table_name> PARTITION (<your_partition_name>)
    PROPERTIES ("enforce_consistent_version" = "false");
3. Verify the Status Check if the repair was successful:
Copy code
sql
ADMIN SHOW REPLICA STATUS FROM <your_table_name> PARTITION (<your_partition_name>);
Important Notes * Data Loss: This repair works by rolling back metadata. You will lose the data that was loaded between the corrupted version and the healthy historical version. You may need to re-ingest recent data for that partition. * Stability: If this continues to happen after the repair, check your FE configuration
lake_gc_expire_seconds
. If it is set too low (e.g., less than 86400), long-running compactions or transactions might lose files to the GC. * Bug in 4.1.1: Version 4.1.x introduced significant changes to shared-data metadata management. If the
ADMIN REPAIR
fails, it is highly recommended to check the FE leader logs for
lake
or
publish
related exceptions and consider reporting this as a potential regression in the 4.1.x branch. Referencessql-reference/sql-statements/cluster-management/tablet_replica/ADMIN_REPAIR.mdadministration/management/resource_management/Replica.mdadministration/management/compaction.mdfaq/shared_data_faq.mdtable_design/table_types/primary_key_table.md Referencesfaq/loading/Loading_faq.md
g
@Rocky
lake_gc_expire_seconds
doesn't appear to be a real config
r
You are absolutely correct to call that out—I apologize for the oversight.
lake_gc_expire_seconds
is not a valid configuration parameter in StarRocks. I likely conflated the names of several similar shared-data (lake) parameters. The actual parameters that control Garbage Collection (GC) and version retention in shared-data mode are: 1.
lake_autovacuum_grace_period_minutes
(Most Relevant)
* Default: 30 (minutes) * Description: This is the "safe zone." It determines how long historical data versions (and their corresponding segment files) are kept after a Compaction has successfully created a new version. * Why it matters for your error: If a Primary Key table is performing a heavy load or a long-running Compaction, the system needs to "look back" at previous segments to build the Primary Index. If this is set too low (e.g., the default 30 minutes) and your operations take longer than that, the AutoVacuum process might delete the segment file while the FE/CN is still trying to reference it, leading to the
Object does not exist
error. * Recommendation: If you are seeing "Object does not exist" errors during
publish
, try increasing this to
60
or
120
in your FE config. 2.
lake_autovacuum_stale_partition_threshold
* Default: 12 (hours) * Description: If a partition hasn't been updated (no loads, deletes, or compactions) within this timeframe, the system stops performing AutoVacuum on it. 3.
shard_group_clean_threshold_sec
* Default: 3600 (1 hour) * Description: The time FE waits before cleaning up unused tablet and shard groups. 4.
catalog_trash_expire_second
* Default: 86400 (24 hours) * Description: How long metadata is kept in the "recycle bin" after you manually run
DROP TABLE
or
DROP DATABASE
. ────────── Summary for your "Object does not exist" issue: The error you encountered is a known "race condition" in shared-data mode where the Garbage Collector is too aggressive for the speed of your Primary Key index builds. Immediate Fixes: 1. Use
ADMIN REPAIR TABLE <name> PARTITION (<p_name>);
to roll back the corrupted metadata to a healthy state. 2. Increase
lake_autovacuum_grace_period_minutes
in your FE configuration to give the system more breathing room during heavy loads. 3. Since you just upgraded to 4.1.1, check if there are any
lake_compaction
tasks that are failing or stuck in the FE leader logs, as failed compactions can sometimes trigger premature cleanup. Referencesadministration/management/FE_configuration.mdsql-reference/sql-statements/cluster-management/tablet_replica/ADMIN_REPAIR.mdfaq/shared_data_faq.mdadministration/management/compaction.md Referencesadministration/management/FE_configuration.md
g
ooo @Rocky i see this in the logs before the missing .dat, could this be the cause? if so, how do i fix? 2026-06-11 001657.311Z WARN (autovacuum-pool1-t8|330) [AutovacuumDaemon.vacuumPartitionImpl():340] Vacuumed events.<mytable>.2822666 with error: starlet err grpc.GetShard(shardId=2822669) error: Deadline Exceeded
r
Yes, that log entry is a major "smoking gun" and is almost certainly related to your missing
.dat
file. The error
starlet err grpc.GetShard(...) error: Deadline Exceeded
means that your FE (Leader) tried to communicate with a CN node (via the "Starlet" service) to manage metadata for that partition, but the request timed out before the CN could respond. How this causes the "Missing .dat" error In StarRocks' shared-data architecture, there is a delicate dance between Compaction (which creates new files and marks old ones for deletion) and Autovacuum (which actually deletes those old files). 1. The Bottleneck: If your CN nodes or FE are under heavy load (CPU spikes, memory pressure, or IO throttling on Azure Blob), these internal metadata requests start timing out (
Deadline Exceeded
). 2. The Inconsistency: When these RPCs time out during critical "Publish" or "Vacuum" phases, the system can get into a state where the Metadata thinks a file should exist, but the Physical Storage cleanup was either triggered prematurely or the write was never fully acknowledged due to the timeout. 3. Primary Key Sensitivity: Primary Key tables are especially vulnerable because they must load the primary index from these files. If one
.dat
file is missing due to an inconsistent metadata update, the entire partition becomes unreadable. How to fix and prevent this 1. Reduce Autovacuum Pressure If the system is timing out, it's often because it's trying to do too much cleanup at once. You can throttle the Autovacuum daemon by adding these to your FE configuration (
fe.conf
)
:
Copy code
properties
# Lower the number of partitions vacuumed at once (Default is 8)
lake_autovacuum_parallel_partitions = 4

# Increase the interval between vacuuming the same partition (Default is 180s)
lake_autovacuum_partition_naptime_seconds = 300
2. Increase the "Grace Period" As mentioned before, increasing the time a file is kept after it is "no longer needed" gives the system a safety buffer in case of timeouts:
Copy code
properties
# Give the system more time before deleting old segments (Default is 30)
lake_autovacuum_grace_period_minutes = 60
3. Check for Azure Throttling or CN Resource Exhaustion * CN Load: Check the CPU and Memory usage on your
kube-starrocks-cn-0
pod at the time of the error (
00:16:57Z
). If CPU was at 100%, the
GetShard
gRPC request was likely stuck in a queue. * Azure Blob: Ensure your storage account isn't hitting ingress/egress limits. StarRocks shared-data performance is heavily tied to the latency of the object store. 4. The "Immediate" Fix for the Table Since the
.dat
file is already gone, the partition is currently "broken." You must run the repair command to tell StarRocks to ignore the corrupted metadata version and roll back to the last version where all files existed:
Copy code
sql
-- This will roll the partition back to its last healthy state
ADMIN REPAIR TABLE <mytable> PARTITION (p2822666);
Summary The
Deadline Exceeded
proves your cluster is struggling to keep up with metadata management. This upgrade to 4.1.1 likely increased the volume of internal metadata traffic. Throttling the Autovacuum and increasing the Grace Period are your best defenses against this happening again. Referencesfaq/Sql_faq.mdfaq/shared_data_faq.mdfaq/loading/Loading_faq.mdknowledge/usage/best-practice.md
g
@Rocky does starrocks attempt a retry later of these timed out vacuums?
r
Yes, the AutovacuumDaemon is a recurring background thread in the Leader FE. It does not have a "retry immediate" logic; instead, it works on a continuous cycle. Here is how the "retry" works in practice: 1. The Cyclic Nature The daemon scans partitions that need cleanup. If a vacuum task for a partition fails (like your
Deadline Exceeded
error), the daemon simply moves on to the next partition. It will attempt to vacuum your partition again in the next cycle, which is governed by the
lake_autovacuum_partition_naptime_seconds
(default 180 seconds). So, the system will try again, but only after the "nap time" has passed for that specific partition. 2. The "Object Not Found" Paradox There is a subtle danger here: * If the vacuum fails (Deadline Exceeded), it usually means it didn't finish deleting files. This is generally "safe" (you just have extra junk in storage). * However, if you are seeing
Object does not exist
errors, it means a vacuum task (or a compaction job) succeeded in deleting a file that the Primary Index still believed was necessary. In StarRocks 4.1.x, this often happens because: 1. Metadata vs. Physical Reality: A previous vacuum cycle might have completed successfully, but due to the high load (indicated by your timeouts), the FE's metadata state and the actual files in Azure Blob became desynchronized. 2. Primary Key Compaction: In version 4.1.1, Primary Key tables use a more aggressive metadata management system. If the
GetShard
call timed out during a compaction or publish phase, the system might have inconsistent pointers to data segments. 3. Why the "Deadline Exceeded" is a warning sign Even though the vacuum retries, the fact that it is timing out suggests your FE/CN communication is saturated. When the Autovacuum daemon hits a deadline, it can leave "stale" metadata behind. If a subsequent load or compaction tries to reference a segment that was partially processed or incorrectly flagged for deletion during that timed-out window, you get the
Not found
error. Recommendations * Don't wait for the retry to fix the "Not Found" error: A retry of the vacuum will not bring back the deleted
.dat
file. The vacuum only deletes; it never restores. * Use
ADMIN REPAIR
: This is your only way to fix the current "Not Found" error. It tells the metadata to "rewind" to a version where that file still existed. * Increase Timeout: If you see frequent
Deadline Exceeded
, you can increase the internal RPC timeout (though this is a BE/CN config and usually handled via
lake_service_rpc_timeout_ms
in newer versions, it's safer to first reduce the load via the FE configs mentioned previously). Summary: The vacuum retries every 3 minutes, but the "missing file" error is a permanent state of the current metadata version that requires a manual
ADMIN REPAIR
or a rollback. Referencesadministration/management/FE_configuration.mdfaq/shared_data_faq.mdsql-reference/sql-statements/cluster-management/tablet_replica/ADMIN_REPAIR.md Referencesadministration/management/FE_configuration.mdfaq/shared_data_faq.mdsql-reference/sql-statements/cluster-management/tablet_replica/ADMIN_REPAIR.md Referencesadministration/management/FE_configuration.mdfaq/shared_data_faq.md
g
@Rocky interesting because I see similar warnings on other partitions but I don't see any errors later so maybe they end up getting vacuumed in the next attempt?
r
Yes, that is exactly what is happening. Your observation is correct: StarRocks handles these as transient failures and will automatically retry them in the next cycle. How the Retry Works The
AutovacuumDaemon
in the Leader FE runs a continuous loop. Here is why those errors disappear: 1. The "Nap Time": When a vacuum task for a partition fails (due to a
Deadline Exceeded
or any other error), the daemon marks that partition as "done for now." It then waits for the duration of
lake_autovacuum_partition_naptime_seconds
(default: 180 seconds). 2. The Next Cycle: Once those 3 minutes are up, the partition becomes eligible for vacuuming again. The daemon will pick it up, recalculate what needs to be deleted, and try the RPC call again. 3. Silence = Success: If you don't see the error again for those partitions, it means the subsequent retry succeeded. The "Deadline Exceeded" was likely caused by a temporary spike in network latency or CN CPU usage that cleared up by the time the next 3-minute window arrived. Why this is both Good and Bad * The Good: The system is self-healing. A temporary timeout doesn't cause a permanent leak of storage space; it just delays the cleanup by a few minutes. * The Bad: The fact that you are seeing these warnings at all means your FE-to-CN communication (the Starlet gRPC service) is hitting its limits. Why you have a "Missing .dat" file but others are fine This is the critical distinction: * Failed Vacuum (The log you saw): The system tried to delete old files but timed out. The files are still there. This is safe. * Successful Vacuum + Timing Race: The "Object does not exist" error happens when a vacuum succeeds in deleting files that the Primary Key index (on a different node or in a different thread) still thinks it needs. Recommended Action Since you are seeing these "Deadline Exceeded" warnings across multiple partitions, your cluster's metadata management is "running hot." You should increase the RPC timeout to give these tasks more time to complete before they error out: In your FE config (
fe.conf
):
Copy code
properties
# Increase internal metadata RPC timeout (Default is usually 5s)
starmgr_grpc_timeout_seconds = 10
This will reduce the number of "Vacuumed with error" warnings in your logs and allow the background cleanup to finish even when the system is under heavy load. Referencesadministration/management/FE_configuration.mdfaq/shared_data_faq.mdadministration/management/compaction.mdadministration/management/BE_configuration.md Referencesadministration/management/FE_configuration.mdfaq/operation_maintenance_faq.mdadministration/management/compaction.mdfaq/shared_data_faq.md
g
@Rocky my starmgr_grpc_timeout_seconds is already 60 seconds
r
If your
starmgr_grpc_timeout_seconds
is already set to 60 seconds and you are still hitting
Deadline Exceeded
, this is a significant red flag. A metadata operation like
GetShard
should typically take milliseconds; timing out after a full minute indicates a fundamental bottleneck rather than a simple configuration issue. What a 60-second timeout implies If the system is exhausting a 60-second window, increasing the timeout further is unlikely to help. It suggests one of the following: 1. CN Node Resource Exhaustion: The CN pod (likely
kube-starrocks-cn-0
) is so overloaded that the gRPC request is sitting in a queue for over a minute before a worker thread can even look at it. Check the CPU and Memory usage of your CN pods specifically at
00:16:57Z
. 2. IO Stall (Azure Blob): The
GetShard
call might be waiting for the CN to fetch or verify something on Azure Blob. If Azure is heavily throttling your storage account or if there's a networking "black hole," the thread will hang until the deadline. 3. FE Global Lock Contention: If the FE (Leader) is busy with a massive metadata update (like a very large
ALTER TABLE
or hundreds of concurrent
PUBLISH
tasks), the
AutovacuumDaemon
might be blocked from even sending the request or processing the result. 4. Thread Pool Exhaustion: Both the FE and CN have gRPC thread pools. If these are full, new requests wait. How to address the "60-Second Deadline" 1. Throttle the Vacuum Concurrency Instead of letting the vacuum tasks wait longer, make them happen less frequently and with less concurrency. This reduces the "queue" on the CN nodes. Add/Update in `fe.conf`:
Copy code
properties
# Reduce concurrent vacuum tasks from default 8 to 2 or 4
lake_autovacuum_parallel_partitions = 2

# Slow down the retry cycle (increase "nap time" between attempts)
lake_autovacuum_partition_naptime_seconds = 600
2. Check for "Long GC" in FE/CN Logs Search your FE and CN logs for
[GC pause]
or
Slow execution
. If the Java process (FE) or the C++ backend (CN) is experiencing long pauses, it can't respond to gRPC heartbeats or requests, leading to a timeout. 3. Monitor CN "Starlet" Health In your CN pod, check the
<http://cn.INFO|cn.INFO>
or
<http://starlet.INFO|starlet.INFO>
logs for errors around the same timestamp. Look for: *
Rejected request
(indicates
lake_service_max_concurrency
hit). *
Storage error
(indicates Azure Blob issues). 4. The "Safety Buffer" (Crucial) Since you are seeing these timeouts, your metadata and storage are in a "race condition." You must increase the grace period to ensure that even if a vacuum is delayed or retried, it doesn't delete files that are still being referenced by slow-moving metadata tasks. Update in `fe.conf`:
Copy code
properties
# Keep files for 2 hours instead of 30 mins to account for these 60s+ lags
lake_autovacuum_grace_period_minutes = 120
Summary of the Fix The fact that you see these warnings on other partitions without errors later confirms the self-healing nature of the vacuum—it eventually succeeds on a retry. However, the one partition that failed with a "missing file" error likely had its files deleted by a different successful vacuum/compaction task while the
GetShard
call for that specific version was still hung/timing out. Immediate Action: 1. Run
ADMIN REPAIR TABLE <mytable> PARTITION (p2822666);
to restore the broken partition. 2. Reduce
lake_autovacuum_parallel_partitions
to 2 to stop the cluster from choking on its own cleanup tasks. 3. Increase
lake_autovacuum_grace_period_minutes
to 120 to prevent future "Not Found" errors during these lag spikes. Referencesadministration/management/FE_configuration.mdfaq/shared_data_faq.mdadministration/management/compaction.md
g
@Rocky is vaccum deletes in the shared-data general grafana dashboard the right metric to look at? if i look at that specific cn, I do see some latency spikes.
r
Yes, Vacuum Deletes in the Shared-data Dashboard is exactly the right metric to monitor. The fact that you see latency spikes on a specific CN in this metric directly correlates with the
Deadline Exceeded
errors you are seeing in your logs. What these metrics tell you: * Vacuum Deletes (Latency/QPS): This tracks how long the CN takes to process the vacuum request from the FE. If the "Quantile Latency" (e.g., P99) spikes toward or above your
starmgr_grpc_timeout_seconds
(60s), the FE will abort the task and throw the
Deadline Exceeded
error. * Vacuum Errors: In the same "Vacuum" section of the dashboard, you should see a corresponding spike in the Errors chart whenever a timeout occurs. Why the CN is showing spikes: Since the vacuum process involves the CN physically deleting files from Azure Blob storage, a latency spike on the CN usually means one of three things: 1. Storage Throttle: Azure Blob might be throttling the delete requests (TPS limits). 2. CN Resource Saturation: The CN's "Starlet" worker threads are overwhelmed, causing requests to sit in the queue. 3. Large Batch Size: If a single partition has a massive number of files to clean up, the "delete" RPC might simply be too large to complete within 60 seconds. Other Metrics to cross-reference: To narrow down why that specific CN is lagging, check these on the Starlet Dashboard: * FSLIB FS METRICS -> filesystem meta operations: Look for spikes in directory listing or file deletion operations. * S3/Azure IO METRICS: Look for high latency in backend storage calls. If Azure latency is high, the StarRocks vacuum will naturally slow down. Recommendation: If these spikes are frequent, the system is struggling to keep up with the volume of garbage data. Reducing
lake_autovacuum_parallel_partitions
to a lower number (like
2
) will reduce the concurrent pressure on that CN, smoothing out those latency spikes and preventing the timeouts. Referencesadministration/management/monitoring/metrics-shared-data.mdfaq/shared_data_faq.mdadministration/management/FE_configuration.md Referencesadministration/management/monitoring/metrics-shared-data.mdfaq/shared_data_faq.mddeployment/shared_data/feature-support-shared-data.mdusing_starrocks/caching/block_cache.mdadministration/management/BE_configuration.md
g
@Rocky i'm seeing a fair amount of this in the logs on cn-0
Copy code
W20260611 14:13:34.124416 140377747093184 lake_service.cpp:381] Fail to publish version: Internal error: prepare_primary_index: load primary index failed: Not found: load_segments failed tablet:2822672 rowset:18 segid:0: starlet err Object <my_storage_account>
dataops-k8-blob/starrocks/c06faf1f-a109-4cf6-a569-f20a4df260be/db49953/2618536/2822666/data/0000000000216206_dbd759c1-b756-4f39-91e6-7a7326797513.dat does not exist
be/src/storage/lake/rowset.cpp:481 load_segments(&segments, false)
be/src/storage/lake/txn_log_applier.cpp:476 value_or_err_L476
be/src/storage/lake/txn_log_applier.cpp:509 prepare_primary_index()
be/src/storage/lake/txn_log_applier.cpp:310 check_and_recover([&]() { return apply_write_log(log.op_write(), log.txn_id()); }). tablet_info={tablet_id: 2822672} txn_ids=txn_id: 2209426
commit_time: 1781186401
combined_txn_log: true
txn_type: TXN_NORMAL
force_publish: false
gtid: 426455023854026752
version=30
r
This log is the "smoking gun" for the issues you've been seeing. It confirms a race condition between your slow Publish process and the AutoVacuum daemon. What is happening in this log: 1. The Context: This is a Primary Key table. In StarRocks Shared-Data mode, when you load data, the "Publish" phase (the final step of a transaction) must update the Primary Index. 2. The Error: To update that index, the CN node needed to load an existing data segment (
.dat
file) to resolve updates/deletes. 3. The Root Cause: The CN asked for the file, but it was already gone from Azure Blob Storage (
starlet err Object ... does not exist
). 4. The Link to your previous warnings: Your vacuum tasks were timing out ("Deadline Exceeded"), but as you suspected, they retried. One of those retries succeeded and deleted this
.dat
file because it thought the file was old/garbage. However, because your system is experiencing high latency (those 60s spikes you saw in Grafana), the Publish task for Transaction
2209426
was still running and actually still needed that "old" file to finish building the new index version. The vacuum was "too fast" (or the publish was "too slow"), and it deleted the floor while the publish task was still standing on it. ────────── Critical Actions 1. Immediate Recovery (The "Bad" News) Because a
.dat
file is physically missing from Azure Blob, this partition (
2822666
) is now corrupted.
*
ADMIN REPAIR
will likely not work because there is no other copy of the file in shared storage to "repair" from. * You must reload the data for this partition. * If possible,
TRUNCATE PARTITION p2822666;
and re-run the ingestion for that time range. * If you cannot reload, you may have to drop and recreate the partition, but the data in that specific
.dat
file is effectively lost. 2. Emergency Config Changes (The Prevention) You need to stop the vacuum from being so aggressive while your CNs are struggling with latency. In
fe.conf
, set these immediately:
Copy code
properties
# 1. Increase the safety buffer from 30 mins to 2 hours. 
# This ensures files are kept much longer after they are "replaced,"
# giving slow Publish tasks plenty of time to finish.
lake_autovacuum_grace_period_minutes = 120

# 2. Reduce the number of partitions being vacuumed at once.
# This reduces the IO load/spikes on your CN nodes.
lake_autovacuum_parallel_partitions = 2

# 3. Increase the "nap" time between vacuum attempts.
lake_autovacuum_partition_naptime_seconds = 600
3. Why the Latency Spikes? The "60-second latency spikes" you see in Grafana are the root of all this. Since you are on Azure: * Check if you are hitting Azure Storage Account Egress/Ingress limits or Request Rate limits (TPS). * If your CNs are in Kubernetes, check if they are being CPU throttled (Cgroup throttles). If the CN is throttled, it can't process the gRPC heartbeats, leading to the "Deadline Exceeded" and the subsequent "Not Found" race condition. Summary The "Deadline Exceeded" warnings you saw earlier were the system's way of telling you it was struggling. Because the vacuum eventually succeeded while a related publish task was still lagging, it deleted a required file. Increase your
lake_autovacuum_grace_period_minutes
immediately
to prevent this from happening to other partitions. Referencesadministration/management/FE_configuration.mdfaq/shared_data_faq.mdadministration/management/monitoring/metrics-shared-data.mdsql-reference/sql-statements/table_management/TRUNCATE_TABLE.md ) References
g
@Rocky the p99 mean and max are 42.2 ms 1.15 s for vaccum deletes, that isn't anywhere near the 60 second timeout
r
The discrepancy between your 60-second timeout and the 1-second execution metric is a classic sign of a Queueing/Metadata Bottleneck rather than an execution bottleneck. Here is why your metrics look "fast" while the system is timing out, and what that log entry really means: 1. Why Metrics (1.15s) vs. Timeout (60s) mismatch? The "Vacuum Deletes" metric in Grafana typically measures the time the CN spent actually calling the storage API (Azure Blob) to delete files. It does not include: * gRPC Queueing Time: If the CN or FE has all its worker threads busy, a request can sit in the gRPC queue for 59 seconds before the "execution" (the 1.15s part) even starts. At 60 seconds, the requester gives up, even if the task was about to start. * FE Metadata Locks:
starmgr_grpc_timeout_seconds
usually applies to the CN talking to the FE's StarManager (metadata service). If the FE is under heavy load (e.g., a massive metadata update or a Java GC pause), it won't respond to the CN's request for metadata. The CN waits 60s and then logs "Deadline Exceeded." Conclusion: The CN is physically fast, but the coordination between FE and CN is "choking." 2. The Log Analysis:
Not found: load_segments failed
This error in
lake_service.cpp:381
is the result of the timeout you’re seeing. * What happened: A transaction (Ingestion) reached the "Publish" phase. For a Primary Key table, the CN must load existing data segments to update the Primary Index. * The Conflict: Because the FE was "choking" (the 60s timeout), the version tracking got out of sync. The AutoVacuum daemon (running on the FE) incorrectly identified the
.dat
file as "garbage" and deleted it because it thought no one was using it anymore. * The Result: When the Publish task finally tried to read that file, it got the "Object does not exist" error. 3. Immediate Recommended Fixes Since your execution is fast but your coordination is timing out, you need to reduce the "Metadata Noise": A. Increase the Safety Buffer (Critical) The vacuum is deleting files while they are still needed because the system is lagging. You must give the system more "thinking time." In `fe.conf`:
Copy code
properties
# Double the grace period so files aren't eligible for deletion for 1 hour.
# This prevents the "Not Found" error during 60s lag spikes.
lake_autovacuum_grace_period_minutes = 60
B. Throttling Vacuum Frequency If the vacuum is triggering too many gRPC calls, it's contributing to the 60s queueing delay. In `fe.conf`:
Copy code
properties
# Default is usually 8. Lowering this reduces gRPC pressure on the FE.
lake_autovacuum_parallel_partitions = 2
# Let the vacuum "sleep" longer between rounds.
lake_autovacuum_partition_naptime_seconds = 300
C. Check FE Thread Health If
starmgr_grpc_timeout_seconds
is being hit, check your FE logs (
fe.log
and
fe.warn.log
) for: *
Slow execution
or
Long GC pause
*
starmgr
related errors. * Check FE Grafana: JVM GC Time and FE Edit Log Flush Latency. If the FE cannot flush its own logs to disk quickly, the metadata service (StarMgr) will hang, causing the 60s timeouts on the CNs. Summary Your partition
2822666
is currently corrupted because a required data file was deleted. 1. Stop the bleeding: Increase
lake_autovacuum_grace_period_minutes
to 60 or 120. 2. Fix the partition: You will likely need to
TRUNCATE
and reload the data for that specific partition, as the physical file is gone from Azure. 3. Monitor FE: Look at FE CPU and GC metrics; the 60s delay is almost certainly happening inside the FE metadata layer where the FE manages metadata, FE manages metadata, not in the CN's deletion logic. Referencesadministration/management/FE_configuration.mdadministration/management/BE_configuration.md
g
@Rocky are there any downsides to changing those configs? old data lives on blob longer?
r
The short answer is yes, but the "cost" is usually negligible compared to the risk of data corruption or query failures. Here is the breakdown of the downsides: 1. Increased Storage Cost (Azure Blob) This is the primary downside. * What stays longer: When a Compaction happens, StarRocks creates new merged files and marks the old small files as "garbage." * How long: By increasing
lake_autovacuum_grace_period_minutes
from 30 to 60 or 120, you are effectively keeping those "garbage" files for an extra 30–90 minutes. * The Cost: Unless you are loading hundreds of Terabytes per hour, the cost of keeping a few extra versions of data for an hour on Azure Blob is typically just a few cents or dollars a month. It is much cheaper than the engineering time required to fix a corrupted partition. 2. Slower Reclaim of Space If you are running a massive "one-time" data delete or a major schema change, the disk space in your storage account won't "shrink" immediately. You’ll have to wait for that grace period to pass before the physical
.dat
files are deleted. 3. Metadata Retention (Minimal Impact) The StarRocks FE (FrontEnd) has to track these "stale" versions in its memory and image until they are vacuumed. * If you set this to something extreme (like 1 week), your FE image size would grow significantly, and it could slow down FE restarts. * Moving from 30 minutes to 2 hours has almost zero noticeable impact on FE metadata performance. 4. Reduced Vacuum "Throughput" By lowering
lake_autovacuum_parallel_partitions
and increasing
naptime
, you are intentionally slowing down the cleanup process. * The Risk: If your ingestion rate is extremely high (thousands of transactions per minute), garbage might accumulate faster than the vacuum can clean it up. * How to monitor: Keep an eye on the "Garbage File Size" or "Garbage File Count" in the Shared-data Grafana dashboard. If you see this number trending up indefinitely over 24 hours, you’ve slowed the vacuum down too much. Recommendation For your current situation—where you are actually losing data because the vacuum is "outrunning" the metadata coordination—*the benefits far outweigh the downsides.* * Set
lake_autovacuum_grace_period_minutes = 60
(or 120). * Set
lake_autovacuum_parallel_partitions = 4
(half of default). This "buys" your system time to handle those 60-second latency spikes without the vacuum daemon accidentally deleting a file that a slow task is still trying to read. Referencesadministration/management/FE_configuration.mdknowledge/admin_and_operation/shared_data_garbage_cleanup.mdadministration/management/monitoring/metrics-shared-data.mdbest_practices/primarykey_table.md Referencesadministration/management/FE_configuration.mdadministration/management/compaction.mdknowledge/admin_and_operation/shared_data_compaction.mdbest_practices/primarykey_table.md
g
@Rocky i don't see garbage metrics anywhere, am i missing something or is there another way i can monitor that?
r
It is completely normal that you don't see a single "Garbage Size" metric in Prometheus. Because StarRocks is a Shared-Data system, it doesn't always know exactly how much physical data is sitting in Azure Blob until it actually performs a vacuum or an audit. Here is how you can monitor garbage and the health of the vacuum process: 1. The "Smoking Gun" Metric Since you are seeing "Not Found" errors, you should add this specific metric to your dashboard: *
starrocks_be_segment_file_not_found_total
: This tracks how many times a CN tried to open a file that was missing from storage. In a healthy cluster, this should be 0. A rising line here confirms that your vacuum is deleting files that the system still needs (the race condition we discussed). 2. Monitoring the "Backlog" (Indirectly) Instead of a single "size" metric, use the Compaction Score to see if garbage is building up. When data is loaded or updated, StarRocks creates new versions. Until compaction merges them and vacuum deletes the old ones, those "stale" versions are essentially garbage. * Query:
SELECT DB_NAME, TABLE_NAME, MAX_CS, AVG_CS FROM information_schema.partitions_meta WHERE MAX_CS > 10;
* Interpretation: A high Max_CS (Compaction Score) means that partition has many historical data files. If this number stays high for hours despite your vacuum running, it means the vacuum is failing or is too slow to keep up. 3. Monitoring Vacuum Activity Check these in your Shared-data Dashboard (or raw Prometheus): *
starrocks_fe_lake_vacuum_deletes_total
: This is a counter. If it’s flat, your vacuum isn't doing anything. *
starrocks_fe_lake_vacuum_errors_total
: If this is increasing, the vacuum tasks are failing (likely due to the 60s gRPC timeouts you saw). *
starrocks_fe_lake_vacuum_duration_ms
: Compare this to your 60s timeout. If it's consistently hitting the ceiling, you need to increase your
starmgr_grpc_timeout_seconds
or reduce parallel vacuum tasks. 4. How to see the "Real" Garbage Amount If you need to know exactly how many GBs of garbage are in your Azure container, you have two options: 1. Manual Comparison: Compare the output of
SHOW DATA
(which only shows the latest visible version) with the total size of the container reported by the Azure Portal. _ _Example:* If Azure says 10TB and
SHOW DATA
says 2TB, you have 8TB of historical versions/garbage. 2. Audit Tool: StarRocks provides a
meta_tool.sh
that can perform a
lake_datafile_gc
operation with
do_delete=false
. It will scan your metadata and your Azure Blob and output exactly which files are unreferenced (garbage). Summary for your Dashboard To prevent the "Not Found" error you experienced, monitor
starrocks_be_segment_file_not_found_total
and the Compaction Scores in
partitions_meta
. If the scores are high and the "Not Found" errors are non-zero, it means your vacuum is too aggressive relative to your system's metadata latency. Referencesadministration/management/monitoring/metrics-shared-data.mdadministration/management/monitoring/metrics.mdfaq/shared_data_faq.mdknowledge/admin_and_operation/shared_data_garbage_cleanup.mddeployment/shared_data/feature-support-shared-data.mdsql-reference/sql-statements/Database/SHOW_DATA.md Referencesadministration/management/monitoring/metrics.md
g
@Rocky I made those changes and things were good for a while but another similar missing
.dat
popped up. What's really curious is I have a different ETL process that is constantly running and has been fine but this one hasn't run for an hour and does this.
r
The fact that this happens after a one-hour idle period while your "always-on" ETL remains stable is a specific pattern. It strongly suggests that your issue isn't just about "missing files" in general, but specifically about how StarRocks handles metadata synchronization for partitions that have "gone cold." Here is the likely root cause and how to address it: 1. The "Cold Partition" Metadata Race In a shared-data cluster, when a partition is idle, the Compute Nodes (CNs) may eventually "evict" the Primary Key index for that partition from memory to save space. * The Problem: When your idle ETL process restarts after an hour, the CN must rebuild the Primary Key index. To do this, it asks the FE for the list of segment files and then tries to load them (
load_segments
). * The Bug/Race: If the vacuum process ran during that idle hour, it might have deleted files that the FE still considers part of the "latest version" due to a metadata lag or a "stale" view of the tablet's history. * Why the "Always-on" ETL is fine: Because that process is constantly writing, its index is always "hot" in memory, and its metadata is constantly being refreshed in the CN's cache. The vacuum never gets a chance to "sneak in" and delete a file that isn't being actively held by a session. 2. Configuration Adjustment:
lake_autovacuum_stale_partition_threshold
There is a specific parameter that controls when StarRocks stops vacuuming "idle" partitions: *
lake_autovacuum_stale_partition_threshold
(Default: 12 hours). * What this does: If a partition hasn't been updated for 12 hours, the vacuum daemon stops looking at it entirely. * The Issue: Your partition is only idle for 1 hour, so it is still being "scanned" by the vacuum daemon every few minutes. If there's any discrepancy in your storage metadata (Azure Blob vs. FE), the vacuum daemon has many chances to accidentally flag an unreferenced file in that 1-hour window. Recommendation: Try reducing this to a smaller window (e.g., 2 hours) to limit the time an idle partition is "exposed" to the vacuum daemon, or ensure it is high enough that the vacuum doesn't act on partitions you plan to resume shortly. However, usually, increasing the grace period (which you did) is the standard fix. 3. Check for "Metadata Lag" on the FE If increasing the grace period to 60 minutes didn't stop the
.dat
files from disappearing, it means the FE believes a file is valid for > 60 minutes after it has actually been physically deleted, or vice versa. * Check your
fe.log
for "starmgr" or "tablet manager" errors. * Search for
fail to commit txn
or
publish version timeout
in the FE logs during the time the ETL was idle. 4. Enable Persistent Index (If not already enabled) If your Primary Key table is large, the "rebuild" process after an hour of idleness is very heavy because it has to load all
.dat
files to recreate the index. Setting the table property:
Copy code
sql
ALTER TABLE your_table SET ("enable_persistent_index" = "true");
By enabling the persistent index, the index itself is stored in Azure Blob. This significantly reduces the need for the BE to "load segments" from the original data files when the ETL restarts, which can bypass the
load_segments failed
error. 5. Final Diagnostic Command When the error happens, run this on the FE to see if the FE and the physical storage are out of sync:
Copy code
sql
-- Replace with your actual tablet ID from the error log
SHOW TABLET <tablet_id>;
Check if the
VisibleVersion
in the output matches what you expect. If the
VisibleVersion
is very old but the files in Azure are gone, your FE's metadata journal might be stuck. Summary of Action Plan: 1. Enable Persistent Index: This is the most robust way to stabilize Primary Key tables in shared-data mode. 2. Verify FE Health: Ensure the FE isn't hitting "Edit Log" or "BDBJE" pressure (look for
HANDSHAKE_ERROR
or
ACK timeout
in
fe.log
).
3. If the error persists: You may be hitting a specific bug in the version of StarRocks you are running related to how the StarManager cleans up metadata; consider checking the release notes for your specific version for "Primary Key storage cleanup" fixes. Referencesadministration/management/monitoring/metrics.mdfaq/loading/Loading_faq.mdadministration/Meta_recovery.mddata_source/datalake_faq.mdfaq/shared_data_faq.md
g
@Rocky what's even more curious is a lot of transformations/transactions have been happening and it seems to always be this particular dataset that gets ugly
r
It’s a strong signal that this specific dataset is your "ugly" one. This behavior usually points to a mismatch between how this specific table is structured and how the Shared-Data Vacuum handles "stale" metadata. Since it’s this specific dataset and it happens after an hour of idleness, here is why it’s likely "getting ugly" for that one and not the others: 1. High Compaction Score (The "Version Trap") This dataset likely has a much higher write frequency or a larger number of small updates than your other ETL. * The Trap: When you stop writing for an hour, the StarRocks FE finally has a chance to trigger "Cumulative Compaction" to clean up the mess left behind. * The Result: If this table produces hundreds of small segment files per hour, the vacuum daemon has thousands of "old" files to delete the moment the ETL goes idle. If your metadata synchronization to Azure Blob has even a 60-second lag, the Vacuum might delete a file that the FE just referenced in a metadata update. * Check: Run
SELECT TABLE_NAME, MAX_CS FROM information_schema.partitions_meta WHERE TABLE_NAME = 'your_ugly_table';
. If
MAX_CS
is significantly higher (e.g., > 30) than your stable tables, this is the cause. 2. Missing "Persistent Index" (Primary Key Tables Only) If this is a Primary Key table, it is the most likely culprit. * The Idle Eviction: When a PK table is idle for an hour, the Compute Nodes (CN) often evict the "Primary Key Index" from memory to save RAM. * The Rebuild: When your ETL starts again, the CN has to rebuild that index. To do this, it must read every single segment file in the table. * The Error: If the vacuum deleted even one historical segment that the FE still thinks is part of the current "version" during that idle hour, the index rebuild fails immediately with a missing
.dat
error. * Fix: Ensure Persistent Index is enabled for this specific table. This stores the index on Azure Blob so the CN doesn't have to "re-read" all the
.dat
files after an idle period.
Copy code
sql
    ALTER TABLE your_ugly_table SET ("enable_persistent_index" = "true");
3. Too Many Tablets/Buckets Check if this "ugly" dataset has a much higher bucket count than the others. * If you have a small dataset but set
BUCKETS 64
or
128
, you are creating a massive amount of metadata for very little data. * The Vacuum process works per tablet. If one table has 2,000 tablets and another has 20, the vacuum for the "ugly" table is under much higher "metadata pressure," making it more likely to hit a race condition or a gRPC timeout. 4. Data Cache Corruption If you have Data Cache enabled on your CN nodes: * Sometimes the cache on a specific CN keeps a "hot" pointer to a file path that was physically deleted from Azure Blob by the vacuum daemon. * Why only this table? If this table is queried or updated by a specific set of CNs, those caches might be "stuck." * Test: Try running
set global enable_scan_datacache = false;
before starting the ETL. If the error goes away, you need to clear the cache on your CN nodes (
rm -rf
the cache directory). Summary Recommendation 1. Check Compaction Score: If it's high for this table, you need to increase the
lake_autovacuum_grace_period_minutes
even further (try 180) specifically for this table's heavy churn. 2. Enable Persistent Index: If this is a PK table, this is almost certainly the fix. 3. Reduce Buckets: If this table is small (under 100GB), ensure it doesn't have hundreds of buckets. Aim for ~1GB to 10GB per bucket. Referencesadministration/management/monitoring/metrics-shared-data.mdfaq/shared_data_faq.mdknowledge/admin_and_operation/shared_data_compaction.md