Changelog
Release notes for the Open Source edition can be found on github.
Unreleased
v0.373.0
-
With
FELDERA_REFUSE_LOCAL_FILE_URIS=true, Delta Lake and Iceberg connectors refuse local paths, such asfile:///etcor/etc, also when a secret or an environment variable holds the path. -
Behavior change (exactly-once Kafka output): the connector no longer limits delivery retries to five, and a failed commit no longer leaves the connector stuck while the pipeline runs. It keeps the records of the open transaction, aborts the transaction after a delivery failure, sends the records again, and commits, with a backoff of up to ten seconds, until the commit succeeds or the pipeline stops. It reports unhealthy while it recovers. A fatal producer error or an unclassified transaction error holds the output thread until the pipeline is stopped instead of dropping later output. Fencing by another instance or by the broker after a transaction timeout requires a restart. Records the client refuses are reported once, even when first discovered during replay. A refusal by the broker, a revoked permission, a missing topic or a transaction longer than
transaction.timeout.msis reported as a connector error after three aborts in a row, and no record is dropped. Above 64 MiB the kept records spill to a file in the pipeline's storage directory. New metricskafka_output_transaction_aborts_total,kafka_output_commit_retries_totalandkafka_output_replay_spool_bytes. See Exactly-once delivery and recovery. -
Enterprise (Kubernetes):
POST,PUT, andPATCH /v0/pipelinesrefuse aruntime_configwith aresources.storage_classorresources.volume_attributes_classthat is not on the allowlist of the installation, or aresources.storage_minorresources.storage_maxabovekubernetesRunner.upperLimitStorageMegabyte, with a 400InvalidRuntimeConfigerror. Before, the API accepted these values and the next start failed. On all installations,storage_mincannot be more thanstorage_max. A pipeline stored with such values still loads. See Storage limits. -
Incompatible change (SQL): date arithmetic now matches the SQL standard. An interval holds whole numbers in every field except
SECOND, and an operation that produces an interval truncates the value toward zero to the last field of its type (see the interval types):- A cast between interval types:
CAST(INTERVAL '19' MONTH AS INTERVAL YEAR)is nowINTERVAL '1' YEARinstead of 19 months, soDATE '2020-01-01' + CAST(INTERVAL '19' MONTH AS INTERVAL YEAR)is now 2021-01-01 instead of 2021-08-01.CAST(INTERVAL '25' HOUR AS INTERVAL DAY)is nowINTERVAL '1' DAYinstead of 25 hours. - A cast of a number with a fraction:
CAST(1.5 AS INTERVAL YEAR)is nowINTERVAL '1' YEARinstead of 18 months, andCAST(-1.5 AS INTERVAL DAY)is nowINTERVAL '-1' DAYinstead of -36 hours. - The product or the quotient of an interval and a number, which has
the type of the interval:
INTERVAL '1' YEAR * 1.5is nowINTERVAL '1' YEARinstead of 18 months, andINTERVAL '1' DAY / 2is nowINTERVAL '0' DAYinstead of 12 hours. - The difference of two dates, times or timestamps, which has the type
of its qualifier and counts the boundaries of its last field between
the two values:
(DATE '2021-01-01' - DATE '2020-12-31') YEARis nowINTERVAL '1' YEARinstead of 0 months, and(DATE '2021-03-01' - DATE '2020-01-01') YEARis nowINTERVAL '1' YEARinstead of 14 months.TIMESTAMPDIFFdoes not change.
- A cast between interval types:
v0.372.0
-
Behavior change (non-fault-tolerant Kafka output): temporary delivery failures are retried without a deadline by default, replacing the former five-minute limit. When the broker is down the producer queue fills, the connector blocks, and the pipeline waits behind it until the broker is back. Set
message.timeout.msor its aliasdelivery.timeout.msin the transport configuration to restore a bound. Permanent errors and explicit timeout or retry limits can still lose records. The connector reports unhealthy after a failed delivery, or when a message has waited ten seconds for delivery with no delivery completed meanwhile, and recovers after successful delivery when no messages remain overdue. Broker connection failures are logged as warnings and no longer counted as connector errors, since the queued records are not lost. Metrics prefixedkafka_output_expose producer queue depth, delivery counts, and queue wait time. See Kafka output delivery and metrics. -
NATS input connector: the client library is updated to async-nats 0.51.0, which fixes spurious missing-heartbeat errors while messages are buffered and pull consumers looping on
409 Exceeded MaxRequest*. Themax_batch,max_bytesandmax_expiryconsumer settings now reach the server, where earlier releases dropped them. A consumer that the library recreates is named<prefix>_<uuid>_<n>, and the connector deletes it together with its own. See consumer lifecycle.
v0.371.0
-
Delta Lake input connector:
uc://tables can use Databricks workload identity federation. Setunity_client_id,databricks_hostandunity_federated_token_file(for example a Kubernetes service account token) instead ofunity_client_secret. See Unity catalog. -
Enterprise (Kubernetes): with the Helm value
mtls.enabled, the compiler, runner, pipeline and coordinator servers require client certificates. A pipeline may only download its own binary and program info, and may not call the runner or another pipeline. Clients that reach a pipeline directly, instead of through the API server, are refused. It requireshttpsSecretRef,caSecretRefand cert-manager. Restart running pipelines after you turn it on.mtls.extraClientUrislets external clients, such as sidecars, call pipelines directly. See client certificates. -
Enterprise (Kubernetes): with
caSecretRefset, pipeline pods mount only the certificate ofhttpsSecretRef, not its key, and the API server mounts only the certificate ofcaSecretRef. -
Incompatible change (Enterprise, Kubernetes): a pipeline can select a Kubernetes service account with
resources.service_account_nameonly if the operator lists the account in the Helm valuepipeline.allowedServiceAccountNames. The list is empty by default, so a pipeline that setsresources.service_account_namefails to start until the operator adds its account. The service account is the pipeline pod's Kubernetes identity: list only accounts without Kubernetes API permissions, such as accounts that only carry an IRSA role. The chart refuses its own control-plane service accounts in the list. -
Incompatible change (Enterprise, Kubernetes): pipeline pods no longer get a Kubernetes API token (
automountServiceAccountToken: false) or the environment variables that Kubernetes adds for each service in the namespace (enableServiceLinks: false). -
Incompatible change:
envin the runtime configuration reserves more names:BASH_ENV,BASHOPTS,ENV,IFS,PATH,PS4,SHELLOPTS,GCONV_PATH,GLIBC_TUNABLES,LOCPATH,NLSPATH,OPENSSL_CONF,OPENSSL_ENGINES,OPENSSL_MODULES, and names that start withBASH_FUNC_orLD_. The API refuses a pipeline that sets one, and an existing pipeline that sets one fails to start until the variable is removed.
v0.370.0
-
Experimental (Enterprise, Kubernetes): a resize of
memory_maxwithPATCH /v0/pipelines/{name}also changes the memory budget of the running pipeline, unlessmax_rssis set. A smaller budget applies at once, so the pipeline moves state to storage before the pod shrinks. A larger budget applies when the pod has grown. See Resizing a running pipeline. -
GET /v0/pipelines/{pipeline_name}/logsacceptsfollow=false, which returns the retained logs and ends the response instead of waiting for new lines. Support bundles use it to collect logs, and so doesfda logswithout--watch. In Python,Pipeline.logs(follow=False)andFelderaClient.get_pipeline_logs(name, follow=False)request it. -
Python SDK:
FelderaClientcan now list, look up and delete API keys (list_api_keys(),get_api_key(),delete_api_key()) and manage the members of the current tenant (list_tenant_members(),add_tenant_member(),set_tenant_member_role(),remove_tenant_member()), matchingfda apikeyandfda member. -
Bug fix (Parquet output): a deletion in the output of a view with a Parquet output connector crashed the pipeline. The connector now reports an encoder error for that batch instead; the Parquet format still cannot represent deletes.
-
Incompatible change (PostgreSQL CDC input connector): a connector whose
source_tablehasINHERITSchildren used to deliver the children's rows in its initial read, but never their later changes. The initial read now delivers the parent's own rows only, as the change stream always did. A pipeline that readspublic.ordersand relied on seeing the rows ofpublic.orders_archive INHERITS (public.orders)gets them after the upgrade only once the child has a connector of its own: runALTER PUBLICATION feldera_orders ADD TABLE public.orders_archiveand attach a secondpostgres_cdc_inputconnector with"source_table": "public.orders_archive"to the same Feldera table. See Inherited tables. -
PostgreSQL CDC input connector: the special values
infinityand-infinityof aDATE,TIMESTAMPorTIMESTAMPTZcolumn, and theTIMEvalue24:00:00, have no counterpart in the Feldera types. A row that holds one is now reported as a malformed record and skipped, like any other row that fails to parse; all other values of these columns are unaffected. The connector used to report an etl decoding error for such a row instead. -
Incompatible change (SQL):
REALandDOUBLE-0.0and0.0are not distinguished. An operation that produced-0e0now produces0e0: for example, casting-xto a string gives0.0whenxis zero, and1e0 / -0e0isInfinity. -
Incompatible change (input formats): an input value of type
DATE,TIME,TIMESTAMPorTIMESTAMP WITH TIME ZONEoutside the legal range is now a parse error. Before this change, such a value was accepted: for example, a timestamp of253402300800000000microseconds in an Avro or Parquet input became10000-01-01 00:00:00. -
Incompatible change (SQL):
<,<=,>and>=are no longer allowed betweenROWvalues, and neither areBETWEEN,GREATEST,LEAST,GREATEST_IGNORE_NULLSandLEAST_IGNORE_NULLSwithROWarguments, so some programs that used to compile are now rejected. The same holds forARRAYandMAPvalues that containROWvalues, such asROW(x INT) ARRAY;=and<>remain allowed on them. These operations placed aNULLfield before any other value, soROW(1, NULL) < ROW(1, 2)wastrue; standard SQL givesNULL. Compare the fields instead, for exampler.x < s.x OR (r.x = s.x AND r.y < s.y). A user-defined type declared withCREATE TYPE ... AS (...)is aROWtype, so the restriction covers its values too.ORDER BY,MINandMAXstill acceptROWvalues. See comparingROWvalues.
v0.369.0
-
Python SDK: the new
reloadable_tablesargument ofPipeline.start(),start_paused(),start_standby(), andrestart()lists the tables that bootstrapping may reload. Withbootstrap_policy=BootstrapPolicy.ALLOW, the SDK approves the bootstrap only if each modified table is in the list. Otherwise it raisesTableReloadNotAllowedError, and the pipeline stays inAwaitingApproval. See Approving reloads of selected tables. -
Avro output connectors encode views with
ROW(user-defined type) columns under a generated schema: eachROWbecomes a nested record, named after its path in the view, such asv_cfor columncof viewv,v_a_itemfor the elements of an array columna, andv_m_valuefor the values of a map columnm. Before, such a view failed with "not implemented: Avro encoding for user-defined SQL types". -
Incompatible change (SQL): a
DATEcomputation whose result is before0001-01-01or after9999-12-31now stops the pipeline with an error. Before this change, such a computation produced an illegal date: for example,DATE '9999-12-31' + INTERVAL '1' DAYproduced10000-01-01. -
Incompatible change (SQL): the same applies to
TIMESTAMPandTIMESTAMP WITH TIME ZONEcomputations, whose legal range is0001-01-01 00:00:00to9999-12-31 23:59:59.999999. -
Incompatible change (SQL): a cast from a number to
TIMESTAMPkeeps the fraction of a second, as documented:CAST(1500 AS TIMESTAMP)is now1970-01-01 00:00:01.500, andCAST(1.5e0 AS TIMESTAMP)is1970-01-01 00:00:00.0015. Before this change, the result had no fractional seconds (1970-01-01 00:00:01). -
Incompatible change (user-defined preprocessors): connector metadata attributes are now
VariantValues instead ofVariants.ConnectorMetadata::get_by_namereturnsOption<&VariantValue>, andConnectorMetadata::get, which took aVariantkey, is removed. Replace a pattern such asSome(Variant::String(topic))withSome(VariantValue::String(topic)), wheretopicis a RustString.feldera_sqllibre-exportsVariantValue. SeeConnectorMetadata. -
Incompatible change (connectors): some connector metadata attributes have new types. Casts such as
CAST(CONNECTOR_METADATA()['avro_schema_id'] AS INT UNSIGNED)andCAST(CONNECTOR_METADATA()['kafka_headers'] AS MAP<STRING, VARBINARY>)give the same results as before; only a program that reads the rawVARIANTvalue can see the difference.- The Avro format reports
avro_schema_idas aBIGINTinstead of anINT UNSIGNED. - The Kafka connector reports a header without a value as a
VARIANTnull instead of a SQLNULLinCONNECTOR_METADATA()['kafka_headers']. - In the
connector_metadataparameter of the HTTP input connector, a non-negative integer is aBIGINTinstead of aBIGINT UNSIGNED, and a number with more than 38 digits is rejected.
- The Avro format reports
-
Bug fix (SQL): a column
DEFAULTthat appliesTYPEOForTO_JSONtoCONNECTOR_METADATA(), and aVARIANTcolumn withDEFAULT VARIANTNULL(), failed to compile. A column default now reads connector metadata as aSqlVariant, like every otherVARIANTvalue, so building a pipeline also no longer reports a deprecation warning for each table and view. -
Bug fix (Delta Lake output connector): with the default
"variant_encoding": "variant", writing aVARIANTthat holds someDECIMALvalues, such as1500000000or0.0000000001, failed, although the Parquet variant encoding can hold them. The connector now writes these values.
v0.368.0
-
In a multihost pipeline, a Kafka input connector can now divide the partitions of its topic among the hosts, and a Delta Lake or Iceberg input connector can divide the data files of its snapshot. Set the new connector attribute
distributedtotrue. See distributed connectors for Kafka, Delta Lake, and Iceberg. -
Incompatible change (SQL): a cast from
DOUBLEorREALtoDECIMALnow gives the same result as Calcite. It uses the shortest decimal form of the value, then truncates it to the scale. Before, the cast sometimes lost a digit or added digits:CAST(0.29e0 AS DECIMAL(10, 5))gave0.28999and now gives0.29000, andCAST(-99.99e0 AS DECIMAL(38, 20))gave-99.99000000000000262144and now gives-99.99000000000000000000. AREALis converted toDOUBLEfirst, soCAST(CAST(0.1e0 AS REAL) AS DECIMAL(38, 20))gives0.10000000149011612000. An input format that gives a binary floating-point value for aDECIMALcolumn now also keeps all the digits of its shortest form, instead of only 16. JSON input does not change. -
Python SDK: preserve view columns and their pandas types when an output batch is empty.
-
Experimental: the Delta Lake output connector can keep a table equal to its view instead of appending a change log. Set
update_modetomerge: the connector appends each new row version and marks the old one deleted in a deletion vector, so a reader sees one live row per key and a flush never rewrites a data file. An existing target table must havedelta.enableDeletionVectorsset, and the pipeline must be the only process writing rows to it.auto_compacthas the connector compact the table itself, which reclaims the superseded rows. See merge mode. -
Incompatible change (
VARIANT, Rust UDFs):VARIANTvalues are implemented by theSqlVariantRust struct. This feature previously requiredSET FELDERA_FLAT_VARIANT = 'ON'.A user-defined function that takes or returns a
VARIANTnow receivesfeldera_sqllib::SqlVariant, which names whichever representationVARIANTuses, rather than the enumfeldera_sqllib::Variant.SqlVariantis not an enum, so code that matched onVariant::String(..)and the other arms needs rewriting. The enum is deprecated and will be removed.Because connectors still report record metadata as the enum, building a pipeline reports one deprecation warning per table and view, naming
Variantin code the compiler generates rather than in anything you wrote. Those warnings are harmless and go away with the enum. Connector metadata itself will move toSqlVariantin a future release, so a preprocessor that matches on the arms of the enum will need rewriting then; seeConnectorMetadata.The storage formats of the two representations are not compatible, so a pipeline with a
VARIANTcolumn rebuilds its state from scratch on upgrade: a view is recomputed from its inputs, and a table re-ingests from its connector. The pipeline does not do this on its own. It reports the tables and views it would rebuild and waits for approval, so an upgrade never discards state without consent.Setting
FELDERA_FLAT_VARIANTtoOFFkeeps the previous behavior on both counts: the program's user-defined functions continue using the legacy representation and need no changes, and the pipeline resumes from its existing checkpoint instead of rebuilding. Set it before the pipeline runs with the new representation: once the pipeline checkpoints, setting it no longer recovers the earlier state.
v0.367.0
-
Pipelines without fault tolerance no longer write a checkpoint on
SIGTERM. On Kubernetes, Force Stop also sendsSIGTERM, so such a pipeline could keep a checkpoint the user did not ask for. -
Incompatible change (SQL compiler): a pipeline compiled with this release cannot reuse the state that an earlier release saved for its views. When the pipeline resumes from such a checkpoint, it must bootstrap all its views from its tables, which takes more time than a typical bootstrap. Materialized tables can reuse their existing saved state.
-
Incompatible change (SQL compiler): a pipeline whose program uses
NOW()cannot resume from a checkpoint that an earlier release saved. Bootstrapping a pipeline compiled with a previous version of the compiler will be impossible. After recompilation stop the pipeline, clear its storage, and start it again. The pipeline then ingests all its input data again. -
Avro input connector: the new
cdc_fieldproperty names a field that holds the operation type of each raw Avro record:I(insert),U(upsert), orD(delete). A Feldera Avro output connector withcdc_fieldset writes these values. See Ingesting change data capture (CDC) records. -
Incompatible change (pipeline process): the pipeline binary reads its configuration file as JSON only, so its
--config-fileargument must name a JSON file. The pipeline manager writesconfig.jsonand no longer writesconfig.yaml. A pipeline binary has preferredconfig.jsonsince release 0.155.0, so a pipeline pinned to that release or a later one is not affected. In the Enterprise edition, the pipelineConfigMapcarries onlyconfig.json. -
Bug fix (Iceberg input connector): in
snapshot_and_followmode, a pipeline that restarted from a checkpoint taken after the connector read the initial snapshot read that snapshot again, so a table without a primary key got duplicate rows. Now the connector continues to follow the table after the last snapshot that it ingested. A checkpoint taken before this fix still makes the connector read the snapshot again once. See Iceberg input connector. -
Deprecation (pipeline and connector configuration): every size setting now takes a string with a unit, in the format Kubernetes uses for a quantity, such as
"16G","4Gi","512Mi"or"4096". Accepted units arek,M,G,T,PandE(powers of a thousand) andKi,Mi,Gi,Ti,PiandEi(powers of 1024), each with or without a trailingB; a bare number is a number of bytes. A setting whose old name counted megabytes or mebibytes refuses a quoted number with no unit, such as"16000", since the unquoted16000meant megabytes: write"16G". Each setting loses the unit from its name, somemory_mb_maxbecomesmemory_max, and the settings whose name carried no usable unit take a name that says what they measure, as the table below shows. The old name remains a deprecated alias of the new one and takes the bare number it always took, so an existing configuration keeps working, and the pipeline logs a warning that names the setting and the value to write instead. Writing both names of one setting is an error. The old names are removed no earlier than release 0.369.0.The NATS consumer's
max_bytesis not part of this scheme: it is a NATS pull option passed through as NATS spells it.Old name (unit) New name max_rss_mb(MB)max_rssdatafusion_memory_mb(MB)datafusion_memorystorage.cache_mib(MiB)storage.cache_sizestorage.min_storage_bytes(bytes)storage.min_spill_sizestorage.min_step_storage_bytes(bytes)storage.min_step_spill_sizeresources.memory_mb_min,resources.memory_mb_max(MB)resources.memory_min,resources.memory_maxresources.storage_mb_min,resources.storage_mb_max(MB)resources.storage_min,resources.storage_maxresources.autoscaling.storage.scale_threshold_available_mb(MB)resources.autoscaling.storage.scale_threshold_availableconnector max_queued_bytes(bytes)max_queued_sizedev_tweaks.storage_mb_max(MiB)dev_tweaks.storage_maxdev_tweaks.fbuf_slab_bytes_per_class,lazy_input_map_key_block_bytes,exchange_channel_capacity_bytes(bytes)fbuf_slab_size_per_class,lazy_input_map_key_block_size,exchange_channel_capacityFile input buffer_size_bytes(bytes)buffer_sizeDynamoDB and Postgres output max_buffer_size_bytes(bytes)max_buffer_sizePostgres CDC batch.max_bytes(bytes)batch.max_sizedeployment_config.resources.memory_mb_min,memory_mb_max(MB)memory_min,memory_maxFor a client that reads the configuration back:
- A configuration is stored under the new names the next time it is saved,
and the API then returns it under those names, as
"16G"rather than16000. A pipeline stored before this change and not saved since comes back under the old names, so a client must accept either. - The OpenAPI schema lists only the new names.
- The Python SDK's
Resources,StorageandRuntimeConfigtake the new arguments as strings such as"16Gi", and read them back from either spelling. The old arguments and attributes such asmemory_mb_maxremain as deprecated properties that return a whole number of the old unit and warn. The SDK writes each setting to the server under the name it was given, so code that uses the old arguments keeps working against an older server. - The web console reads the memory and storage limits of a pipeline from either spelling.
Upgrade
fdatogether with the server. Anfdaolder than this change reads a configuration stored under the new names as if those settings were unset.fda set-configtakesmemory_min,memory_max,storage_min,storage_max,max_rss,datafusion_memoryandmin_spill_sizeas sizes; its megabyte and byte keys keep working and say which key to use.When the pipeline manager starts a pipeline pinned to an older runtime with
runtime_version, or one compiled by an earlier release and not yet updated, it writes the pipeline's configuration under the old names, in the runtime configuration and in every connector. A size that is not a whole number of the old unit rounds up, so a small limit never becomes0. A runtime from before the duration rename gets both the old duration and the old size names; one from between the two renames gets only the old size names. The configuration stored by the API is not changed. - A configuration is stored under the new names the next time it is saved,
and the API then returns it under those names, as
-
Incompatible change (pipeline process): the pipeline binary reads its configuration file as JSON only, so its
--config-fileargument must name a JSON file. The pipeline manager writesconfig.jsonand no longer writesconfig.yaml. A pipeline binary has preferredconfig.jsonsince release 0.155.0, so a pipeline pinned to that release or a later one is not affected. In the Enterprise edition, the pipelineConfigMapcarries onlyconfig.json.
v0.366.0
-
Incompatible change (ad-hoc queries): the
hashresult format andPipeline.query_hash()in the Python SDK return a different hash for the same rows than earlier releases. Compare only hashes taken from the same release. -
Incompatible change (ad-hoc queries and connector filters): ad-hoc queries, and the
filterandsnapshot_filterproperties of the Delta Lake and Iceberg connectors, now evaluate some SQL differently. Filters that compare a timestamp or date with a string, such asts > '2024-01-01', are not affected.- A number compared with a string is compared as a number, not as text.
For example,
bigint_col BETWEEN '10' AND '20'now selects the values from 10 to 20. A string that is not a number makes the query fail, instead of matching nothing. sqrtof a negative number andpower(0, -1)fail, instead of returning NaN and infinity.- A scalar subquery that returns more than one row fails.
medianof an integer column returns a floating-point value.-0.0and0.0are equal and group together.EXTRACT(ISODOW FROM ...)returns 1 (Monday) to 7 (Sunday), instead of 0 to 6.CAST(json_get(...) AS VARCHAR)returns the JSON text of a number, boolean, object or array, instead of NULL.valuesis no longer accepted as a column alias withoutAS: writeSELECT x AS values, notSELECT x values.
- A number compared with a string is compared as a number, not as text.
For example,
-
Incompatible change (Delta Lake connectors): DynamoDB commit locking on S3 is no longer supported. If the storage parameters set
AWS_S3_LOCKING_PROVIDER = 'dynamodb', the connector logs an error and ignores it. Commits use conditional writes, which stop two writers from overwriting each other's commit on a store that supports them, such as Amazon S3. -
Incompatible change (Delta Lake connectors): the connector properties
aws_profile,aws_role_arn,aws_web_identity_token_fileandaws_role_session_nameno longer have an effect. Set the matching environment variables (AWS_PROFILE,AWS_ROLE_ARN,AWS_WEB_IDENTITY_TOKEN_FILE,AWS_ROLE_SESSION_NAME) in the pipeline's environment instead, as IRSA on Amazon EKS does.aws_regionstill selects the S3 region, but to assume an IAM role, also setAWS_REGIONin the environment. Other properties, such asaws_access_key_idandaws_secret_access_key, work as before. -
Delta Lake input connector: in
snapshotmode, an empty string in a string partition column now reads as''instead of NULL, the same as infollowmode. Afilterorsnapshot_filterthat compares a string partition column with a number, such aspart = 2024, now reads all files instead of only the matching partition, and fails if a partition value is not a number. Writepart = '2024'instead. -
Iceberg input connector:
- When the connector reads a snapshot, it matches the columns of a data file
without field ids by the table's
schema.name-mapping.defaultproperty, instead of by column position. - The
gcs.service.pathproperty is renamed togcs.service.host. The old name still works. - Each read call has a time limit, set by
opendal.io-timeout-ms. The default is 60 seconds.
- When the connector reads a snapshot, it matches the columns of a data file
without field ids by the table's
-
Incompatible change (Parquet and Delta Lake output, ad-hoc queries): a
MAPvalue with a NULL key can no longer be written to Parquet or Delta Lake, or returned by an ad-hoc query. This fails withcannot serialize null into non-nullable array. Parquet does not allow NULL map keys. -
Deprecation (pipeline and connector configuration): every duration setting now takes a string with a unit, such as
"500ms","30s","1h30m"or"30d". Accepted units arens,us(orµs),ms,s,m,h, andd, and several terms in a row are summed. Most settings keep their name with the unit dropped, soclock_resolution_usecsbecomesclock_resolution; the others take a new name, as the table below shows. The old name remains a deprecated alias of the new one, so an existing configuration keeps working, and the pipeline logs a warning that names the setting and the value to write instead. Writing both names of one setting is an error. The old names are removed no earlier than release 0.368.0.The Delta connector's
log_retention_durationis not part of this scheme: it passes a"interval 30 days"string through to Delta Lake and keeps its own syntax.Old name (unit) New name max_buffering_delay_usecs(µs)max_buffering_delayclock_resolution_usecs(µs)clock_resolutionprovisioning_timeout_secs(s)provisioning_timeoutfault_tolerance.checkpoint_interval_secs(s)fault_tolerance.checkpoint_intervalstorage.backend.config.ioop_delay(ms)storage.backend.config.ioop_latencystorage.backend.config.sync.pull_interval(s)storage.backend.config.sync.standby_pull_intervalstorage.backend.config.sync.push_interval(s)storage.backend.config.sync.checkpoint_push_intervalstorage.backend.config.sync.retention_min_age(days)storage.backend.config.sync.min_retentionmax_output_buffer_time_millis(ms)max_output_buffer_timeURL input pause_timeout(s)pause_lingerKafka input group_join_timeout_secs(s)group_join_timeoutKafka output initialization_timeout_secs(s)initialization_timeoutNATS connection_timeout_secs,request_timeout_secs,inactivity_timeout_secs,retry_interval_secs,publish_timeout_secs(s)the same names without _secsNATS consumer max_expires({secs, nanos}object)max_expiryPub/Sub timeout_seconds,connect_timeout_seconds(s)timeout,connect_timeoutAvro registry_timeout_secs(s)registry_timeoutFor a client that reads the configuration back:
- A configuration is stored under the new names the next time it is saved, and the API then returns it under those names. A pipeline stored before this change and not saved since comes back under the old names, so a client must accept either.
- The OpenAPI schema lists only the new names.
- The Python SDK's
RuntimeConfigreads.clock_resolutionand the other duration attributes as strings such as"1ms", whichever name the configuration holds. The old attributes such as.clock_resolution_usecsremain as deprecated properties that return a whole number of the old unit and warn. The SDK writes each setting to the server under the name it was given, so code that uses the old arguments keeps working against an older server. - An output connector stored by an earlier release shows its buffer time as
"213503982334d14h25m51s615ms". This is the old default of 2^64 - 1 milliseconds, means the same, and can be left alone.
Upgrade
fdatogether with the server. Anfdaolder than this change reads a configuration stored under the new names as if those settings were unset, andfda set-configthen writes defaults over every duration setting it did not change.When the pipeline manager starts a pipeline pinned to an older runtime with
runtime_version, or one compiled by an earlier release and not yet updated, it writes the pipeline's configuration under the old names, in the runtime configuration and in every connector. A value that is not a whole number of the old unit rounds up, so a short timeout never becomes0. The configuration stored by the API is not changed. In the Enterprise edition, pinning a runtime older than this change does not compile, because the platform's enterprise crates, which such a pipeline builds against, use the new settings. Also in the Enterprise edition, checkpoint garbage collection now keeps a checkpoint for the fullmin_retention: it no longer subtracts a one-hour allowance for clock skew, so a checkpoint may be kept up to an hour longer than before.In a rolling upgrade of a pipeline with a standby, upgrade the standby before the leader: a standby on an earlier release cannot read a checkpoint the upgraded leader writes.
fda set-configtakesmax_buffering_delayandclock_resolutionas durations, and itscheckpoint_intervalkey accepts a duration such as5mas well as the bare number of seconds it took before. -
Pipelines write a checkpoint on
SIGTERMbefore they exit. See Writing checkpoints. -
Bug fix (Python SDK):
Pipeline.checkpoint(wait=True)returned normally when the checkpoint failed. It now raisesRuntimeErrorwith the error the pipeline reported, asPipeline.sync_checkpoint(wait=True)already did. -
Bug fix (Python SDK): the connector methods (
input_connector_stats(),pause_input_connector(),generate_completion_token()and the others) failed withUnknownEndpointfor a quoted table or view name that contains a character such as#,?,%or/. -
The pipeline manager's
--pg-embed-portoption (environment variableFELDERA_PG_EMBED_PORT) sets the port of the embedded Postgres instance, which was fixed at 8082. The default is still 8082.
v0.365.0
-
New connector (
nats_output): write view output to a NATS subject. The connector publishes to JetStream: each message is acknowledged by the server before the pipeline moves on, every message carries aNats-Msg-Idderived from its content so that output replayed after a restart is deduplicated by the server within the stream's duplicate window, and static headers can be attached to every message. The message size limit is discovered from the bound stream at connect time (the stream'smax_message_size, else the server's max payload) and can be overridden; a record over the limit fails the pipeline with an error naming the record and the limit, instead of reaching the server. See NATS output connector. -
New experimental option (SQL):
FELDERA_LAZY_UPSERT = ONmakes the pipeline use an optimized implementation for tables with a primary key. This implementation does not support partial updates (JSONupdateevents). The option is off by default. A change of the option can make the pipeline re-ingest its input data. SeeFELDERA_LAZY_UPSERTand Bootstrapping. -
Experimental (Enterprise, Kubernetes):
deployment_configinPATCH /v0/pipelines/{name}changes the CPU and memory of a running pipeline without a restart, andGETreturns them. The resize lasts across restarts until storage is cleared or CPU or memory is changed in the runtime configuration. Enable it with the Helm valuekubernetesRunner.enablePipelineResize. See Resizing a running pipeline. -
Behavior change (Enterprise, Kubernetes): pipeline StatefulSets now use the
OnDeleteupdate strategy. To apply StatefulSet changes (e.g.,kubectl rollout restart,kubectl edit, etc.), delete the pod.
v0.362.0
-
Incompatible change (SQL): the
emit_finalproperty of a view must specify a column name. The documentation also allowed a column number, such as'emit_final' = '0', but the compiler ignored numeric values: the view emitted every change, as if it had noemit_finalproperty. A column number is now a compilation error. Seeemit_final. -
Incompatible change (SQL): a view with an
emit_finalproperty can no longer be used in the definition of another view. The other view read the rows beforeemit_finalheld them back, not the final rows. Define a separate view withoutemit_finaland use that view instead. Seeemit_final. -
Bug fix (SQL): casting a
DATE,TIMESTAMP, orTIMESTAMP WITH TIME ZONEto a string now pads the year to four digits:CAST(DATE '0001-01-01' AS VARCHAR)is'0001-01-01'. For years before 1000 the result used to omit the leading zeros ('1-01-01').
v0.360.0
-
Storage now uses LZ4 compression by default, instead of Snappy. LZ4 compresses better in about the same amount of time and decompresses several times faster.
-
Incompatible change (SQL):
PARSE_JSONnow fails at runtime if its argument is not valid JSON. It used to return a value thatIS NULLdid not recognize asNULL, although the documentation promised a SQLNULL. The new functionTRY_PARSE_JSONreturns a SQLNULLfor invalid JSON; replacePARSE_JSONwithTRY_PARSE_JSONin programs whose input may hold invalid JSON. SeeTRY_PARSE_JSON.
v0.358.0
-
Incompatible change (SQL): a
RANGEwindow frame with a bound of the formn PRECEDINGorn FOLLOWINGnow requires anORDER BYcolumn that cannot beNULL. A program using e.g.,RANGE BETWEEN INTERVAL 1 DAY PRECEDING AND CURRENT ROWover a nullable timestamp, now fails to compile. This can be worked around by declaring the columnNOT NULL, or by filtering out theNULLvalues first, for example withWHERE ts IS NOT NULL. See Unsupported operations. -
Bug fix (Python SDK):
Pipeline.listen()andPipeline.foreach_chunk()returned aNULLvalue of aCHARorVARCHARcolumn as the string'None'. These columns now have the pandas typestring, so aNULLvalue is a missing value (Noneinto_dict()), andpandas.isna()finds it. -
NATS input connector: retries now back off exponentially with jitter, from
retry_intervalup to the newretry_max_interval(default5m). A connector that previously retried every 5 seconds now waits up to 5 minutes between attempts while NATS stays unavailable; setretry_max_intervalequal toretry_intervalto restore a fixed interval. The new optionalretry_max_attemptsstops the connector with a fatal error after that many consecutive failed retries. -
NATS input connector: JetStream consumers are now always named
<prefix>_<uuid>, where the prefix isconsumer_config.nameor the table name, and are deleted when the connector pauses, stops, retries, or finishes a replay, instead of waiting for the server to expire them. A consumer whose create request timed out is deleted too, since an overloaded server may still create it after the client has given up. -
NATS input connector: new metrics
input_connector_nats_consumers_created_total,input_connector_nats_consumers_deleted_total,input_connector_nats_consumer_delete_failures_total,input_connector_nats_retries_total,input_connector_nats_consecutive_failures, andinput_connector_nats_retry_state. -
NATS input connector: the pipeline name is now injected into the JetStream consumer's metadata under the
pipelinekey, so consumer metrics can be correlated with pipeline metrics (e.g.prometheus-nats-exporterwith-jsz_consumer_meta_keys=pipeline).
v0.356.0
-
Bug fix (SQL):
DATEDIFF(QUARTER, left, right)mixed whole years with calendar quarters and often returned wrong values; for example,DATEDIFF(QUARTER, DATE '2020-06-15', DATE '2021-01-01')returned -1 instead of 2. It now divides the elapsed months by 3, asTIMESTAMPDIFF(QUARTER, left, right)does, so views using it may produce different results after they are recompiled. -
Incompatible change (user-defined aggregates): the accumulator type of a user-defined aggregate written in Rust must now implement
dbsp::dynamic::OrdReprfor its rkyv archived form, so that an archived value can be ordered against an unarchived one without deserializing it. Storage searches file-backed data by comparing archived keys, and every type that can be a key or a value of a Feldera collection needs the comparison; the same therefore holds for any type used as a key or a value with thedbspcrate's Rust API. A type whoseArchiveandOrdare both derived can add#[derive(feldera_macros::OrdRepr)], which compares the fields in the order#[derive(Ord)]does. A type with a hand-writtenArchiveimplementation, such as theI256Wrapperaccumulator in the documentation, needs a hand-writtenimpl OrdRepr<T> for ArchivedTwhoseord_cmpagrees with the type'sOrdon every pair of values; a disagreement makes lookups return wrong rows. Without the implementation the pipeline fails to compile withthe trait bound ... OrdRepr<...> is not satisfied. See User-defined aggregates.
v0.352.0
- Cluster monitoring data that has gone stale is now reported as such
instead of being served as current. The cluster monitor is the only
writer of cluster monitor events, and in the enterprise edition it runs
within the runner, so when the runner dies, its last write kept reporting
every service healthy indefinitely. Once the latest event is older than
30 minutes it carries
stale: true,GET /v0/cluster_healthzreportsall_healthy: falseand answers503, and the web console shows a banner instead of an "Operational" status. This also affects retries: the Rust and Python clients call that endpoint after a502to decide whether to retry immediately, so while monitoring is down they wait their fixed pause instead.
v0.351.0
-
Incompatible change (PostgreSQL CDC input connector): an unqualified
source_tablenames a table in thepublicschema. A pipeline whosesource_tablegives a bare name for a table outsidepublicno longer matches that table, and fails to start with an error that lists the tables the publication carries. Give the qualified name instead, for example"sales.orders". See PostgreSQL CDC input connector. -
The PostgreSQL CDC input connector never checkpoints part of a table's initial read. It blocks checkpoints and suspend requests until the whole read has reached the circuit and the connector's replication state records it, which can take as long as the read of a large table, longer while the pipeline is paused, and may need a forced stop. A pipeline that stops or crashes before a read finishes, a fault-tolerant pipeline that starts with no checkpoint, and a pipeline that resumes from a checkpoint taken before a later read of the table finished all read the table again; a primary key on the Feldera table makes the repeated rows replace the originals. After upgrading, a fault-tolerant pipeline whose table had no changes since its initial read reads it once more, because earlier checkpoints carry no record of the read. See PostgreSQL CDC input connector.
-
Bug fix (PostgreSQL CDC input connector): a fault-tolerant pipeline no longer loses changes when it crashes. The connector reads changes in batches, and it could tell PostgreSQL that a batch was safely held while part of that batch was still on its way into the pipeline. A checkpoint taken at that moment held only the part that had arrived, while PostgreSQL, told it could move on, stopped offering the rest, so a crash before the next checkpoint lost those changes. The connector now reports a batch only once all of it has arrived, and waits for the checkpoint that holds it rather than for one that may predate it when an output connector runs behind. Stopping a pipeline now also reports the batches a checkpoint already holds, instead of leaving them unreported: an unreported batch made the next start read the whole source table again, which a large table made expensive (#7122). See PostgreSQL CDC input connector.
-
The PostgreSQL CDC input connector moves to a newer etl. It no longer fails intermittently with
Missing shared table statewhen a table hands off from its initial read to streaming. etl runs more migrations on the source database: a second source migration extends itsALTER TABLEevent trigger toALTER PUBLICATION, which needs the same superuser privileges as the first, and four state-store migrations, one of which retypes thesnapshot_idcolumns in schemaetl, so an earlier Feldera version cannot start a CDC pipeline against a source database this version has migrated unless theetlschema is dropped first, which repeats every table's initial read. The initial read uses etl's current defaults: batches of up to 32 MiB instead of 8 MiB and four copy connections per table instead of two. See PostgreSQL CDC input connector.
v0.350.0
-
The pipeline logs stream can be resumed instead of replayed from the start of the buffer. Passing
cursor=<epoch>:<sequence>toGET /v0/pipelines/{pipeline}/logsreturns only the lines that follow that position, and the response reports where the stream starts in thefeldera-logs-epoch,feldera-logs-seqandfeldera-logs-gapheaders. A request without acursorbehaves as before. In Python, usePipeline.resume_logsorFelderaClient.resume_pipeline_logs, which returns the open stream and itsLogPosition. -
Bug fix (Delta Lake input connector,
cdcmode): a CDC read no longer decodes columns the pipeline does not need. A column the SQL table never declares, and that no connector expression names, is left out of the read. This also fixes a transaction such asUPDATEorMERGEthat rewrote a file while changing only such a column: itsaddandremoveactions did not cancel, and the connector re-emitted the rewritten rows as inserts (#7116). -
Bug fix (Delta Lake input connector): a Unity Catalog Uniform table read every column as NULL in
followandcdcmode and in the follow half ofsnapshot_and_follow. Its columns are now matched by field id. -
Bug fix (Delta Lake input connector,
cdcmode): auc://table read no rows from a commit's files unless they carried a deletion vector. Such a table's location is path-less, so the listing the read planned resolved to nothing (#7112). -
Bug fix (Delta Lake input connector): a struct nested in an array or a map of a column-mapped table read its neighbor's values in
followandcdcmode, because its fields were paired by name and such a file shares no field name with the table's schema. -
Bug fix (Delta Lake input connector,
snapshotmode): a struct nested in an array or a map of an id-mapped table read its fields exchanged when the log listed them in a different order than the data file. A container's children are now relabeled by field id before the struct cast pairs them (#7279). -
Incompatible change (Delta Lake input connector): in
followandcdcmode a data file holding a null element of an array or a map the Delta table declaresNOT NULLis now rejected. Such a file used to read through, so a pipeline ingesting one now fails where it did not before. -
Incompatible change (SQL compiler): the
WATERMARKcolumn annotation is removed, and a table that declares one no longer compiles. There is no replacement. The annotation was experimental and undocumented, and a table that combined it with aPRIMARY KEYnever compiled.WATERMARKis no longer a reserved keyword, so a program may use it as an identifier, and a column'swatermarkproperty no longer appears in a program's schema. -
The Kafka connector's
sasl.mechanism = OAUTHBEARERauthentication can now target GCP Managed Service for Apache Kafka, in addition to AWS MSK. Set the newoauth_providerfield togcpto mint tokens from Google Application Default Credentials, including the GKE metadata server under Workload Identity. See Kafka input connector (#6886). -
The NATS input connector implements the authentication methods its schema already declared: a bare
nkeyseed (Ed25519 challenge-response),jwtwith the seed that signs the connection nonce (decentralized/operator-mode auth with the JWT and seed as two secrets rather than one.credsfile),token, anduser_and_password. Previously onlycredentialstook effect and the rest were silently ignored; configuring more than one method is now rejected. A newtlssection inconnection_configsetsrequire_tlsandroot_certificates_filefor servers whose certificates a private CA signs. See NATS input connector. -
Behavior change (SQL compiler): a program that declares
LATENESS, declares anappend_onlytable, or filters withNOW()now gets anUnbounded statewarning for each join, aggregate,DISTINCT, window function, or primary-key index whose state may grow without bound. Existing pipelines of this kind compile with warnings, and a program that setsFELDERA_WARNINGS_ARE_ERRORS = ONfails to compile until the state is bounded or the warning is silenced withSET FELDERA_IGNORE_WARNING_UNBOUNDED_STATE = ON. See Unbounded state warnings. -
The SQL compiler emits the warning
Floating point equalityfor constructs that compareREALorDOUBLEvalues for equality: comparison operators,IN,GROUP BY,DISTINCT,UNION,INTERSECT,EXCEPT,PARTITION BY,NATURAL JOIN,USING, and the ties ofRANK,PIVOT, and the array and map functions that compare elements or keys. Each warning points at the clause that compares.SET FELDERA_IGNORE_WARNING_FLOATING_POINT_EQUALITY = ONsilences it; a program that setsFELDERA_WARNINGS_ARE_ERRORSand compares floating point values no longer compiles until it does. See comparing floating point values.
v0.344.0
-
The Delta Lake and Iceberg input connectors read a
VARIANTcolumn stored in the Parquet variant binary encoding, which is how Delta Lake'svarianttype stores one. Values keep the types the writer encoded, so a date inside aVARIANTarrives as a date rather than as a string. AVARIANTcolumn stored as JSON text still reads as before, and the two can sit side by side in one table. -
Breaking change (Delta Lake output connector): a
VARIANTcolumn is now written as the Deltavarianttype rather than as JSON text in astringcolumn, so values keep the types they have in Feldera. Setvariant_encodingtojson_stringfor the previous encoding, which is also what appending to a table whoseVARIANTcolumn is already astringrequires. See VARIANT.
v0.343.0
-
The
bloom_false_positive_ratestorage setting now applies when a Bloom filter is read as well as when it is written. Lowering it and restarting a pipeline reduces Bloom filter memory without rewriting any batches, and raising it again restores the accuracy the batches were written with. See Memory management.Batches written at a rate finer than 0.1 use a new filter format, so a checkpoint written by this or a later version cannot be resumed by an earlier version. Checkpoints written by earlier versions continue to be read.
v0.340.0
-
Output connectors can be paused, like input connectors: a paused output connector discards the output of its view instead of writing it to its sink, which lets a pipeline run on while a sink is unavailable. Set
pausedin the connector configuration to create it paused, and usePOST /v0/pipelines/{pipeline}/views/{view}/connectors/{connector}/{start,pause}orfda connector <pipeline> <view> <connector> start|pauseat runtime. The connector status reports apausedfield, the web console shows it, and the paused state survives a restart. Output produced while a connector is paused is not replayed when it is started. See connector orchestration. -
Python:
Pipeline.pause_input_connectorandPipeline.start_input_connector(and theirFelderaClientcounterparts) name the kind of connector they act on, matching the newpause_output_connectorandstart_output_connector.pause_connectorandresume_connectorstill work but are deprecated and now raise aDeprecationWarning. -
Breaking change (fda):
--auth-token-commandandFELDERA_AUTH_TOKEN_COMMANDare removed.--oidc-token-fileandFELDERA_OIDC_TOKEN_FILEtake the path of a file holding a bearer token, whichfdareads once per invocation;feldera/oidc-auth-actionv3.0.1 and later export that variable. For a command that prints a token, pass its output as--auth "$(...)".
v0.337.0
-
Breaking change (SQL): comparing a
UUIDwith a character or binary value now converts that value to aUUID, the same direction as comparing a string with a number. Previously theUUIDwas converted to the other operand's type, sou <> ''was alwaysFALSE. A value that does not denote aUUIDis now a runtime error rather than a comparison that silently fails (#6883). -
Breaking change (SQL): converting a string to a
UUIDnow follows PostgreSQL: 32 hexadecimal digits of either case, optionally enclosed in braces, optionally separated by a hyphen after any complete group of four digits. Forms such as123e4567e89b12d3a456426655440000and{123e4567-e89b-12d3-a456-426655440000}are now accepted, while the URN formurn:uuid:123e4567-e89b-12d3-a456-426655440000is rejected, as are strings with leading or trailing blanks. Malformed strings are rejected instead of denoting a differentUUID: the literalUUID '1-2-3-4-5'used to mean00000001-0002-0003-0004-000000000005.UUIDliterals follow the same rules as the cast. Converting a binary value to aUUIDnow requires exactly 16 bytes; a longer value used to be truncated. See UUID operations. -
/checkpointand/checkpoint/syncnow return anincarnation_uuidthat can be used with their corresponding status calls to detect if the pipeline restarts. If it does, the operation itself must be restarted (the most common use of the Python API does this automatically).
v0.333.0
-
Breaking change (SQL):
=,<>and!=are no longer allowed betweenROWvalues, so some programs that used to compile are now rejected. The previous implementation of these operations did not follow the standard SQL semantics, which requires thatROW(NULL) = ROW(NULL)evaluates toNULL(in our implementation it would evaluate toTRUE).Instead of these operators, use
IS NOT DISTINCT FROM(or its shorthand<=>) andIS DISTINCT FROMinstead. A user-defined type declared withCREATE TYPE ... AS (...)is aROWtype, so the restriction covers its values too.The restriction also covers the forms that ask for
ROWequality without writing=: a join condition,NATURAL JOIN,USING,IN,CASE value WHEN,NULLIF, and a comparison between two row constructors such as(a, b) = (c, d). See comparingROWvalues for the accepted rewrite of each form. -
Joining on
ROWvalues is now supported, usingON left.r IS NOT DISTINCT FROM right.r(#3398).
v0.330.0
-
Feldera's membership table now authorizes every login: a user acts in the tenants they hold a membership in, whether or not the token's
tenantsclaim names them. The claim, the issuer tenant, and the per-subpersonal tenant become provisioning strategies that create memberships at login, gated by the newauthorization.provisionOnLogin(defaulttrue). Set it tofalseso that access comes only from memberships granted throughPOST /v0/tenant/usersand the web console, with no claim mapping maintained at the identity provider. See Tenant Assignment Strategies and the migration guide. -
Breaking change (revocation): narrowing a token's
tenantsclaim no longer revokes access, because membership rows from past logins stay live. WhileprovisionOnLoginistrue, removing a member does not keep them out either: the claim re-enrolls them on their next login, so full revocation takes both levers. Audit memberships per tenant withGET /v0/tenant/usersbefore or right after upgrading, and see Revoking access. Managed tenancy (thetenantsclaim) is deprecated in favor of Feldera-managed memberships. Two smaller visible changes: some login-path refusals answer403or400where they answered401, and a claim entry a multi-tenant user does not select no longer creates a missing tenant at login (create tenants explicitly withPOST /v0/tenants). -
Member lists now carry the name and email the identity provider holds for each member, and whether that provider vouches for the email, so an administrator recognizes a member without decoding an OIDC
sub.GET /v0/tenant/usersgainsdisplay_nameandemail_verified; the web console's member list andfda member listshow both. -
Renaming a tenant no longer requires updating identity provider claim mappings once
provisionOnLoginisfalse: memberships reference the tenant by id, not by name. -
Owners can retrieve a single tenant by name or identifier through
GET /v0/tenants/{tenant_id}orfda tenant get, so provisioning automation such as an operator reconcile loop checks for a tenant with one request instead of filteringGET /v0/tenants. See Changing your authentication setup. -
POST /v0/tenantsis now idempotent: creating a name that already exists returns the existing tenant with200 OKinstead of failing with409 Conflict, and a fresh name still returns201 Created. Both responses carry the tenant'sid,name, andinitial_provider.fda tenant createis the CLI counterpart.
v0.329.0
- Backward-incompatible change in the
dbspcrate Rust API: theadd_input_setoperator was removed, together with theSetHandletype and the dynamic variantsdyn_add_input_setanddyn_add_input_set_mono. To keep set semantics (duplicate inserts and deletes of absent elements are no-ops), useadd_input_mapwith the element as both key and value; its upsert semantics subsumes set semantics. If the input contains no duplicates,add_input_zsetis a cheaper alternative, but the caller must guarantee that weights stay 0 or 1. SQL pipelines are not affected: the SQL compiler never generated input sets.
v0.328.0
-
Input connectors support the
soft_deleteproperty, which ingests deletions as insertions and reports the original polarity of each record in theis_deletemetadata attribute, so that a table represents the stream of updates it receives rather than the current contents of that stream. See Soft deletes. -
Connectors that ingest columnar data, e.g., Delta Lake, Iceberg, and the Parquet format, now populate columns that default to
CONNECTOR_METADATA(). Previously such a column was alwaysNULLfor these connectors.
v0.327.0
-
Role-based access control (RBAC). Access is now governed by per-user, per-tenant roles (
read<write<admin<owner) rather than every authenticated user having full access to their tenant. See Roles for the model.Upgrading an existing authenticated installation: before RBAC every authenticated user had read and write access; after the upgrade a returning user starts with no membership and is admitted at the configured default role. Set
authorization.defaultRole: write(the binary default isread; the Helm chart sets it towriteinvalues.yaml) so returning users keep their read and write access, and setauthorization.ownersto bootstrap a platform owner, who can then grantadminto whoever manages users and OIDC trust. The default role is applied and recorded on a user's first login after the upgrade, so set it before the first post-upgrade logins; changing it later does not re-grade users who have already logged in (an owner or admin adjusts those individually). TightendefaultRoleback toreadonce explicit roles are provisioned. -
A tenant is now identified by its name alone. Before, a tenant was keyed by
(name, OIDC issuer), so changingauth.issuercreated a second, empty tenant of the same name and stranded the pipelines on the first one, which no login could reach. Logins now resolve the existing tenant across an issuer change. A deployment whose issuer already changed holds two tenants of the same name: the upgrade keeps the name on the one its users reach today and appends the id to the other's name, merging and deleting nothing.GET /v0/tenantslists both. -
Owners can rename a tenant, through
PATCH /v0/tenants/{tenant_id}or the web console's admin page. A rename changes only the name, which is what a login resolves, so it is how an owner reunites users with a tenant they can no longer reach: thedefaulttenant after authentication is switched on, or a tenant left behind by an identity-provider change. Passdisplace_existingto take a name the first login already created a tenant under; that tenant becomes<name> (<id>)and keeps everything it had. See Changing your authentication setup. -
Breaking change (API keys): the
scopesarray on API-key responses (GET /v0/api_keys,GET /v0/api_keys/{api_key_name}) is replaced by a singlerolestring, one ofreadorwrite(lower-case). Clients that read thescopesfield must readroleinstead. Existing keys are migrated towrite, so their access is unchanged. -
Breaking change (API keys): a new key now defaults to
readinstead of carrying read and write access.POST /v0/api_keyswithout arolefield creates aread-only key; pass{"role": "write"}to keep the previous behavior.fda apikey createdefaults to--role readfor the same reason; pass--role writewhere a key needs to make changes.
v0.325.0
- The SQL compiler was incorrectly garbage-collecting input tables with a primary key and a column with LATENESS (#6690). Such tables can only be GC-ed if the column with LATENESS is part of the primary key. As a result some programs that used to run with finite state will now have unbounded state.
v0.322.0
-
Pipeline API field
deployment_runtime_status_detailsis now strongly typed, whereas before it was just a generic JSON value type. WhileAwaitingApproval, the diff is now located atdeployment_runtime_status_details.approval_diffinstead of being the whole details itself. -
Pipelines from v0.322.0 onward will have their GET selector
status_with_connectorsconnector stats cached, which are now updated along with the runtime status details within roughly 1-15s.
v0.319.0
- Cluster monitor events with information on the backing (Kubernetes) resources is
no longer gated behind unstable feature
cluster_monitor_resources(deprecated). It is now enabled by default. This change adds RBAC permissions to get the deployments of the API server and the runner. The status of the backing Kubernetes resources is shown in the Feldera Health page to every (authenticated) user. The cluster monitoring of resources can still be disabled by setting in the Helm chartdisableClusterMonitorResourcestotrue.
v0.316.0
- A bug fix introduced a backward incompatible change to the replay journal format. This only affects pipelines configured with exactly-once fault tolerance. Such pipelines should not be upgraded to the new Feldera runtime if they are in a failed state with non-empty replay journal. Upgrade is possible once the pipeline has been cleanly stopped without a failure.
v0.313.0
-
New DynamoDB output connector. It writes a SQL view to an Amazon DynamoDB table, mapping inserts and updates to upserts and deletes to deletes keyed by the table's primary key. See the connector documentation for configuration details.
-
Pipelines now have a
tagsfield: free-form labels for organizing and filtering pipelines, exposed across the API,fdaCLI, web console, and Python SDK (PipelineBuilder(tags=...),pipeline.modify(tags=...),pipeline.tags()). -
Editing only a pipeline's
descriptionortagsno longer bumps itsversionorrefresh_version, nor triggers recompilation. These fields can therefore be edited at any state of a pipeline (e.g. while running).
v0.311.0
- The default value of
max_output_buffer_size_recordsis now 10,000,000 instead of unbounded.
v0.309.0
-
Rust compiler will clean up the
targetdirectory automatically when its usage reaches the disk limit. This is currently behind the unstable feature flagrust_compiler_full_cleanup. -
Pipeline name is now limited to 63 characters and must follow the Kubernetes label pattern (and be non-empty and contain no dots as before). The check is only enforced when the pipeline is being newly created, its
namefield is being PATCHed or it is getting fully updated via PUT even if the name does not change. Otherwise, existing pipelines with a now invalid name will continue to function. This change is not backward compatible for scripts that create pipelines with names that are no longer valid, in which case they will now receive an error instead of succeeding. However, especially in the Kubernetes runner these pipelines would already not work.
v0.307.0
- Casts of strings to Boolean and floating point values will produce runtime errors instead of legal values for illegal string values. The set of strings that can be legally converted to Booleans has been changed.
v0.306.0
-
No longer allowed to edit
runtime_config.resources.storage_classif the pipeline storage is not cleared. -
Calling
/starton a pipeline that already failed to compile will directly return an error instead of the runner later on setting thedeployment_errorduring its check whether to proceed to provisioning. -
New
max_queued_bytessetting for input connectors. The default is 1,000 timesmax_queued_records, whether that is explicitly set or the default of 1,000,000. This is a change in behavior, since previously there was no byte limit. We believe that the new behavior is generally an improvement that will prevent using excessive memory or even running out of memory but, to restore the previous behavior, specify a large number formax_queued_bytes. -
Delta Lake output connector:
log_retention_duration and
enable_expired_log_cleanup config options to control transaction-log retention on newly created
tables.
Both are only applied at table creation ( i.e. new table or truncate mode ); against an existing table they are ignored. Defaults are unchanged (Delta Lake's own: 30 days, cleanup enabled).
The connector now logs a warning at startup when checkpoint_interval,
log_retention_duration, or enable_expired_log_cleanup in the connector config
differs from the existing table's metadata.
- Large Delta Lake, Iceberg scans (e.g. Delta CDC
ORDER BY) and ad-hoc queries now share a bounded memory pool and spill to disk under<storage>/datafusion-tmp/.
A new runtime_config.datafusion_memory_mb setting controls the pool size
(defaults to 5% of the pipeline's memory budget, capped at 2 GB).
v0.294.0
The HTTP egress API endpoint now accepts a connector configuration as the JSON body. This allows more control over connector configuration. For example:
curl -s -N -X POST 'http://127.0.0.1:8080/v0/pipelines/PIPELINE_NAME/egress/VIEW_NAME' --json '{"format": {"name": "json", "config": {"array": true}}}'
v0.292.0
Pipeline monitoring: Feldera now monitors and persists a pipeline's health.
Events are queryable via /v0/pipelines/[pipeline]/events?selector=[all|status]
and a specific event via /v0/pipelines/[pipeline]/events/[<event-id>|latest]?selector=[all|status].
All API clients support these endpoints. The Web Console will soon expose these
events via a tab too.
v0.289.0
API changes:
- (New) Details about the storage status is a new pipeline field:
storage_status_details. It does not get get cleared when the pipeline stops, only when the storage is cleared. - (Fix) Dedicated error
BootstrapPolicyImmutableUnlessStoppedfor repeated/startof a pipeline but with a different bootstrap policy. - (New) Recent per-endpoint connector error messages are now persisted in the pipeline
checkpoint and restored on resume, so debugging information survives a restart. The
/statsendpoint gains an opt-in?include_connector_errors=trueselector that inlines these messages alongside the counters; the default response is unchanged so hot pollers stay lightweight. The support bundle collector uses the selector automatically. - (Checkpoint format) Backwards-compatible extension:
CheckpointInputEndpointMetricsandCheckpointOutputEndpointMetricsgain optionalparse_errors/transport_errors/encode_errorsfields. Old checkpoints load as empty lists; checkpoints with no errors still serialize without the new keys, so unaffected files stay byte-identical.
CAST(variant AS VARCHAR) will return a meaningful value for all
scalar variant values, and not just for VARIANT objects with a
string value. In the past this cast used to return NULL.
(CAST(string AS VARIANT) AS type) will now behave like
CAST(string AS type). Previously the result was NULL.
Conversion of short intervals including seconds to strings will now include the fractional seconds as well. Previously the fractional seconds were ignored.
v0.288.0
Delta Lake input connector error handling behavior change:
In the past if the connector wasn't able to read a table version, it signaled an error and moved to the next version. This could cause data loss. With this change the connector will either retry forever or fail and stop producing input after exhausting retry attempts.
The second behavioral change is that the connector can now produce duplicate inputs even without a pipeline restart as the connector retries processing delta log entries.
Functions RLIKE and REPLACE_REGEXP will crash for invalid
regular expressions. Previously they treated such as expressions
as expressions which never match. The new behavior more closely
aligns with other databases.
v0.281.0
New dbt adapter for Feldera (dbt-feldera)
A new dbt adapter that lets you build streaming data pipelines using standard dbt workflows. Install from PyPI:
pip install dbt-feldera
Feldera's DBSP engine automatically incrementalizes every query, so incremental models
get true IVM without watermarks or manual merge logic.
Supported materializations: table, view, incremental, seed, and
streaming_pipeline.
See the README for configuration and usage details.
Starting a pipeline while storage is still clearing (storage_status=Clearing) now returns
CannotStartWhileClearingStorage instead of succeeding. Clearing storage while a start
is in progress but hasn't yet transitioned to Provisioning now returns
StorageStatusImmutableUnlessStopped instead of succeeding.
Backward-incompatible Delta Lake output connector change. The new max_retries setting configures
the number of times the connector retries failed Delta Lake operations like writing Parquet files
and committing transactions. The setting is unset by default, causing the connector to retry
indefinitely. This behavior prevents data loss due to transient or permanent write errors.
Checkpoint sync: read_bucket and checkpoint loading priority
The checkpoint sync configuration now supports a read_bucket field — a read-only
fallback bucket used to seed a pipeline's initial state. The pipeline never writes
to read_bucket.
Checkpoint sources are now resolved in priority order:
- Local checkpoint — if the pipeline already has a local checkpoint, it resumes from that without contacting any remote bucket.
bucket— the pipeline's own S3-compatible bucket. If a checkpoint is found here, it is used andread_bucketis ignored.read_bucket— consulted only when both local storage andbucketare empty. This allows a new pipeline to seed from another pipeline's checkpoint, avoiding a full backfill.read_bucketmust point to a different location thanbucket.
Refer to the checkpoint sync documentation for details.
NATS input connector retry and health check support
The NATS input connector now supports automatic reconnection with configurable retry behavior. Two new configuration fields have been added:
inactivity_timeout_secs: Maximum time in seconds to wait for the next message before running a stream/server health check.retry_interval_secs: Delay between automatic reconnect attempts while in retry mode.
The connector now supports pause and resume (start) lifecycle operations, validates replay and resume sequence bounds, and provides improved error messages during retries and health checks.
NATS input connector timeout and probe updates
- The default value for
inactivity_timeout_secshas been increased from10to60seconds. - Health probes now avoid duplicate JetStream stream-info requests, reducing API pressure during retry and recovery loops.
NATS retry classification during resume and replay validation has also been refined: transient failures while fetching JetStream stream metadata are now treated as retryable, while logical sequence-range validation failures remain fatal.
v0.278.0
Checkpoint sync: remote checkpoints older than v0.225.0 are no longer supported
Checkpoints pushed to object storage by a Feldera pipeline older than v0.225.0 can no longer be used with Feldera v0.278.0 or later. Remote checkpoints must be stored as zip archives; the legacy unzipped format is no longer accepted.
v0.263.0
Added connector error list to input/output connector stats. Input and output status endpoints now list up to 100 most recent transport, parser, and encoder errors of each type.
In addition, the openapi spec for both endpoints now specifies strongly typed return values
of type InputConnectorStatus and OutputConnectorStatus respectively.
v0.252.0
Python API removed ignore_deployment_error
The ignore_deployment_error parameter has been removed from the Python
pipeline.start() method. Instead, make use of the newly added dismiss_error parameter.
If you do not want the pipeline to start if there is a pre-existing deployment error,
you should call pipeline.start(dismiss_error=False). Otherwise call pipeline.start()
which is by default equivalent to pipeline.start(dismiss_error=True) (preserving
existing behavior). If the start results in an error occurring, the method will still
throw an error as before. A pipeline deployment error can now also be separately dismissed
using a dedicated endpoint and the corresponding client functions (e.g.,
pipeline.dismiss_error() for the Python client).
Kafka input connector synchronize_partitions option
The Kafka input connector has a new setting synchronize_partitions. When it is
set to true, the connector will read messages in order of their Kafka timestamps
across partitions. Refer to the documentation for more information.
0.227.0
Loading data from checkpoints made in earlier versions of feldera (0.226.0 and below) are not compatible with versions 0.227.0 and above. When upgrading to a version >=0.227, existing pipelines should be backfilled rather than starting from a previous checkpoint.
0.226.0
The Delta Lake connector's skip_unused_columns property has been deprecated. Use
table-level skip_unused_colums
instead.
0.201.0
Cluster monitoring: Feldera now monitors the control plane components (api-server,
kubernetes-runner and compiler-server) health and stores these as events in the
database. They are exposed via /v0/cluster/events and further details of a specific
event can be retrieved via /v0/cluster/events/[<id>|latest].
The /v0/cluster_healthz endpoint now returns the latest recorded event.
All API clients support these endpoints. The Web Console will soon expose these
events via a panel too.
It monitors both what the services report themselves, as well as the status of the
resources backing them. The resources monitoring feature is not yet stabilized,
but can already be activated by adding cluster_monitor_resources to the
Helm chart unstableFeatures array value. The kubernetes-runner, being responsible
for the monitoring, is configured with an additional RBAC permission needed for this
feature (see kubernetes-runner-rbac.yaml for changes).
0.188.0
Prometheus metrics output now also contains pipeline names with a "pipeline_name" label, in addition to the exist "pipeline" label, which still contains the pipeline UUID.
0.186.0
The Kafka input connector will now start reading partitions added to a topic upon resuming from a checkpoint. Previously, the pipeline would not start in this case. Please refer to the Kafka input connector documentation for details.
0.156.0
BACKWARD-INCOMPATIBLE PYTHON SDK CHANGES
- The
Pipeline.listenmethod can now only be called when the pipeline is running or paused. Previously it was possible to callPipeline.listenbefore starting the pipeline in order to guarantee that all outputs produced by the pipeline are captured by the listener. With the new API, you can achieve the same by starting the pipeline in a paused state usingPipeline.start_pausedand callingPipeline.listenbefore unpausing the pipeline usingPipeline.resume.