Snowflake Driver

Snowflake Driver Diagram

The Snowflake driver streams OAS tag data directly into a Snowflake table using the Snowpipe Streaming REST API v2. There are no staging files, no COPY INTO job and no warehouse running for ingestion. Rows are appended over HTTPS and are queryable within seconds of leaving the engine.

PropertyDescription
DirectionWrite only. The driver never reads from Snowflake into a tag.
TransportHTTPS, Snowpipe Streaming REST API v2
AuthenticationKey pair (RSA / JWT) or Programmatic Access Token
DeliveryExactly once per channel, resumed across restarts
BufferingStore and Forward, oldest first
LicensingRequires the Snowflake licensed option

Overview

Every row the driver sends carries an offset. Snowflake remembers the last offset it committed for the channel, and on reconnect the driver asks where it got to and resumes from there. A driver disable, an engine restart or a machine reboot therefore neither loses rows nor repeats them.

Because Snowflake rows are columns rather than documents, this driver has no message format to design. The table is the contract. A Column Mapping names each column, its Snowflake type and which tag property fills it, and the mapping editor generates the matching CREATE TABLE statement for you.

The mapping is also ISA-95 aware: any column can be filled from the tag's position in an equipment hierarchy, such as Enterprise, Site, Area, Work Center, Work Unit, all resolved by walking the groups enclosing the tag. An ISA-95 Lite preset lays out a unified namespace table in one click.

Minimum Configuration Requirements

These are the driver fields that need a value before the driver will connect. Everything else on the driver has a working default.

Driver fieldExample used on this pageWhere the value comes from
Account Identifierabcdefg-xy12345The subdomain of your Snowflake URL - see Account identifier
Authentication TypeKey Pair JWTThe driver default. See Authentication
UserOAS_SVCThe Snowflake user you create. Key-pair only - a token identifies its own user
Private Key PEM or Private Key Pathgenerated by the driverGenerate Key…, or a key pair you already have
Programmatic Access Token-Only if you chose token authentication instead of a key pair
DatabaseOAS_DBCreated in Snowflake
SchemaOAS_DATACreated in Snowflake. Deliberately not defaulted to PUBLIC
TableOAS_TAG_VALUESCreated in Snowflake, or by the driver - see Table creation
Column Mappingthe Default preset plus the three metadata columns - seven in allThe mapping editor
Tags to Publishyour own tagsThe tag picker. Leaving this empty is a configuration error

Pipe, Channel Name, Account Host Override and Ingest Host Override are left blank on a normal installation. Each is described under Configuration.

Important

The names below are examples. Substitute your own.

Every SQL statement on this page uses the same set of example names, and none of them are required or special:

Example nameWhat it is
abcdefg-xy12345The account identifier - yours will be different, and using this one will fail
OAS_SVCThe Snowflake user the driver authenticates as
OAS_STREAM_ROLEThe role holding the grants. Not a driver field - the driver never sends a role, it uses the user's default role
OAS_DB / OAS_DATA / OAS_TAG_VALUESThe database, schema and table the rows are written to

Change them to match your account's naming before running anything, and keep them consistent across the statements. The grants have to name the same objects the driver is pointed at.

Requirements

  • An OAS installation licensed for the Snowflake option
  • A Snowflake account with Snowpipe Streaming available
  • A Snowflake user, role and target table, created by a Snowflake administrator
  • Outbound HTTPS from the OAS engine to your Snowflake account host and streaming host

Warning

An unlicensed driver raises a latching License system error and is refused before its configuration is even examined:

"Snowflake driver: not licensed on this system. Contact your OAS representative to add the Snowflake option."

Check the license first when a driver never connects and Snowflake shows no activity at all.

Preparing Snowflake

OAS does not browse or create objects in your account. These steps are performed in Snowflake, by a Snowflake administrator.

Account identifier

The account identifier is the whole subdomain of your Snowflake URL: everything before .snowflakecomputing.com.

https://abcdefg-xy12345.snowflakecomputing.com
        └─────────────┘
        the Account Identifier

In Snowsight, the Snowflake web interface, go to Admin → Accounts, open the ... menu on your account and choose Manage URLs.

Important

Do not use the LOCATOR column on the Accounts page. It looks like an identifier, it is right there on screen, and it does not work. Authentication fails with a bare 401 that explains nothing.

It is not a full URL either, and not an app.snowflake.com link.

User and role

Tips

Already have a service user and role for OAS? Skip to Target table.

Nothing here is specific to this driver. Any Snowflake user whose default role holds the grants below will work. Note the user name for the driver's User field and move on.

Manually create a Role and a User in Snowsight, or use the SQL below to generate them. The names OAS_STREAM_ROLE and OAS_SVC below are examples and used throughout this documentation. Substitute your own.

CREATE ROLE  IF NOT EXISTS OAS_STREAM_ROLE;
CREATE USER  IF NOT EXISTS OAS_SVC
    DEFAULT_ROLE = OAS_STREAM_ROLE
    MUST_CHANGE_PASSWORD = FALSE;

GRANT ROLE OAS_STREAM_ROLE TO USER OAS_SVC;
ALTER USER OAS_SVC SET TYPE = SERVICE;

Info

The driver never sends a role. The role that applies is the user's default role, which is why it is set above. There is no Role field on the driver.

TYPE = SERVICE marks the account as a machine identity. It cannot log in interactively and is not prompted to change a password.

Target table

The Snowflake Driver needs a target database, schema, and table for writing data. In the OAS Configuration, you will be mapping data values to Snowflake table columns. As a convenience feature, the OAS Configuration Application will provide the SQL statement to create the table within the configured database and schema based on the specified columns and data types.

In the example below, the most basic OAS Tag properties are mapped to table columns, and the tool provides convenient presets for filling in column mappings, including a preset for ISA-95 style Equipment Hierarchy fields.

Additionally, there are Snowflake Metadata Columns you can map that assist with tracking data through Snowpipe. These are highly recommended, and they use specific Column Names that cannot be altered.

OAS Configuration Application - Column Mapping Interface
Snowflake Column Mapping

OAS Configuration Application - Generated Table Creation SQL
Snowflake Column Mapping

If the table already exists in SNOWFLAKE, leave it alone and point the driver at it, then make the Column Mapping match its columns rather than the other way round. OAS never alters or drops an existing table.

Grants

Specific minimum privileges are required for the connected user account to write data into Snowflake from OAS. These are USAGE on the DB and schema, and INSERT on the table. The following is how you can apply these in SQL.

GRANT USAGE  ON DATABASE OAS_DB                         TO ROLE OAS_STREAM_ROLE;
GRANT USAGE  ON SCHEMA   OAS_DB.OAS_DATA                TO ROLE OAS_STREAM_ROLE;
GRANT INSERT ON TABLE    OAS_DB.OAS_DATA.OAS_TAG_VALUES TO ROLE OAS_STREAM_ROLE;

Info

Those three grants are the entire permission surface for streaming. No warehouse, no CREATE PIPE, no OPERATE, and the driver never issues DROP or ALTER.

Two optional grants add optional features: a metadata read privilege lets the driver check the mapping against the real columns on connect (preflight), and CREATE TABLE on the schema lets it create the table for you. Both are safe to omit.

The pipe

Snowflake creates a default pipe for every table, named <TABLE>-STREAMING, when the channel is first opened. Leave the driver's Pipe field blank to use it. Set a name only where a custom pipe performs in-flight transformation. A custom pipe needs MATCH_BY_COLUMN_NAME = CASE_SENSITIVE and GRANT OPERATE ON PIPE to the role.

Authentication

The two options for authentication between OAS and Snowflake are Key Pair (JWT) and Programmatic Access Token (PAT). The following describes the various features and limitations of each type. It is highly recommended to use a Key Pair in a production environment as there is no expiration. This will reduce the chances of the driver failing unexpectedly.

Key Pair JWT (default)Programmatic Access Token
LifetimeUnlimited1–365 days, default 15
RenewalNone - the driver signs its own assertion every 55 minutes, with no network callA person must generate and paste a new token
Network policyNot requiredMandatory for service users
Snowsight supportNone; SQL onlyFull
Right forProduction and anything unattendedGetting started quickly

Key pair

If you do not already have a key pair, use Generate Key… beside Private Key Path in the driver. It writes to the Private Key PEM field or to a file on the engine machine - the Browse… button browses the engine machine, not your workstation - with an optional passphrase that is filled in for you.

Snowflake Key Path

Snowflake Keypair Generator

The dialog then produces two things:

  1. The ALTER USER statement with the public key already in it, BEGIN/END markers stripped. It is shown once. Copy it before closing the dialog.
  2. The key's fingerprint, for comparing against Snowflake.

Important

OAS does not register the key for you. Run the ALTER USER statement in a Snowsight worksheet as ACCOUNTADMIN. Until you do, authentication fails.

To generate a key pair yourself instead:

# unencrypted
openssl genrsa 2048 | openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -out rsa_key.p8

# encrypted
openssl genrsa 2048 | openssl pkcs8 -topk8 -inform PEM -outform PEM -v2 aes-256-cbc -out rsa_key.p8

Tips

On Windows, OpenSSL ships with Git for Windows at C:\Program Files\Git\usr\bin\openssl.exe.

Register the public key as one line with the markers removed:

ALTER USER OAS_SVC SET RSA_PUBLIC_KEY='MIIBIjANBgkq…IDAQAB';

Key rotation uses RSA_PUBLIC_KEY_2 and does not interrupt streaming.

Supported key formats

First line of the fileSupported
-----BEGIN PRIVATE KEY-----Yes
-----BEGIN ENCRYPTED PRIVATE KEY-----Yes, with the passphrase
-----BEGIN RSA PRIVATE KEY-----Yes
-----BEGIN RSA PRIVATE KEY----- followed by Proc-Type: 4,ENCRYPTED and DEK-Info:No

The last form is what openssl genrsa -aes256 produces, and .NET cannot read traditional OpenSSL encryption. Convert it:

openssl pkcs8 -topk8 -in rsa_key.pem -out rsa_key.p8

The fingerprint does not change, so the key does not need re-registering.

Verifying the fingerprint

DESC USER OAS_SVC;
SELECT VALUE FROM TABLE(RESULT_SCAN(LAST_QUERY_ID())) WHERE PROPERTY = 'RSA_PUBLIC_KEY_FP';

The value must match the fingerprint shown by the Generate Key dialog, character for character. Identifiers in these statements must be unquoted.

Info

This check is worth the thirty seconds. Snowflake answers a mismatched key with a bare 401 naming neither keys nor accounts nor claims, so confirming the fingerprint permanently rules out the key as a cause of any later failure.

Programmatic access token

In Snowsight, open the user under Admin → Users & Roles → Users, find Programmatic access tokens and choose Generate new token. The secret is displayed once and cannot be retrieved - copy it immediately.

A service user additionally needs a network policy, or an authentication policy carrying PAT_POLICY = ( NETWORK_POLICY_EVALUATION = ENFORCED_NOT_REQUIRED ). Key-pair authentication has no such requirement.

The User field disappears when this option is selected, because the token identifies its own user.

Important

The token has an expiry date, and on that date the driver stops streaming and reports an authentication failure with nothing in the configuration having changed. Record the date.

Configuration

Below is a comprehensive list of each configuration option on the Snowflake Driver with a description of its purpose and what effect it will have.

Connection

PropertyDefaultNotes
Account Identifier-The subdomain of your Snowflake URL, including the hyphen. Case-insensitive. Not the locator.
Account Host OverrideblankReplaces the host built from the identifier. For PrivateLink, government regions, or a legacy locator needing region and cloud segments. Host name only.
Authentication TypeKey Pair JWTKey-pair does not expire, which is why it is the default for something that runs unattended.
User-Key-pair only; a token identifies its own user.
Private Key PEM / Path / PassphraseblankPaste the key, or point at a file. Leave the passphrase blank for an unencrypted key.
Programmatic Access TokenblankExpires. Record the expiry date and replace it before streaming stops.
Ingest Host OverrideblankSnowflake assigns each account a separate streaming host and the driver discovers it on every connect. Set this only where the discovered host is unreachable, such as over PrivateLink. When set, the driver uses it exactly and reports a failure rather than quietly finding another host.

Target

PropertyDefaultNotes
Database / Schema / Table-Text fields; the driver does not browse the account. Schema is deliberately blank rather than PUBLIC.
PipeblankBlank uses the default <TABLE>-STREAMING pipe.
Channel NameblankBlank generates one from the node and driver interface names.
Create Table If MissingoffCreates the table from the column mapping on connect. Needs CREATE TABLE on the schema.
Fail On Uncommitted RowsoffRefuse to open or drop a channel that still has rows in flight from a previous session.
Column Mappingthe Default preset plus the three metadata columnsThe whole output contract. Edited through the mapping editor, stored as JSON.

Important

Two engines using the same channel name against the same pipe will disconnect each other. Leave Channel Name blank unless you have a specific reason not to.

Publishing

There is no Publish Selected Tags switch on this driver - publishing is all it does, so the switch is hidden.

PropertyDefaultNotes
Tags to Publish-Individual tags, or a group rule written by the tag picker where * matches one level and ** any depth. Rules re-resolve on start and on change.
Publish TypeContinuousContinuous · Event Driven (with a Trigger Tag and Digital Trigger Type) · Specific Time of Day.
Publish Interval10 sContinuous only.
Publish On Startupon
Publish Latest Value OnlyonTurn this off for a historian target, so that no intermediate change is discarded.
Include All Tags Each Publishoff
Include Tags For Periodoff
Override Value When BadNoneHold the last good value, set a fixed value, or hold then set.
Enable Store and Forwardoff

Info

A driver with no tags selected is a configuration error, not an idle driver. It reports "Snowflake driver is not fully configured: Tags To Publish (no tags are selected)" rather than connecting and streaming nothing. A group rule that currently matches no tags counts as none.

Batching and transport

Rows accumulate and are sent when any of three limits is reached.

PropertyDefaultNotes
Max Tags Per Publish1000Rows in one append request.
Max Request Bytes3145728Uncompressed size of one append. Deliberate headroom under Snowflake's hard limit.
Max Latency1000 msHow long to accumulate when neither other limit is reached. Lower is more responsive; higher gives larger, better-compressed batches that are cheaper to query.
CompressionGzipZstd is about half the size of Gzip for the same processor time. None is for debugging, so the payload can be read as it is sent.
Request Timeout30000 ms
Max Retries3Only failures that may resolve on their own are retried - a rate limit, a temporary server error - never a rejection.
Retry Backoff500 msInitial delay; increases with each attempt.

Important

Changing Max Latency, Max Retries, Retry Backoff or Max Tags Per Publish does not drop the channel.

Changing the account, host, credential, database, schema, table, pipe, channel name, compression or request timeout does, because those identify the channel - and dropping the channel restarts STREAM_OFFSET at zero. Keep that in mind when experimenting on a live driver.

Test Connection

Test Connection performs exactly three checks and reports each separately, along with the account host it built, the ingest host Snowflake returned and the User-Agent it sent.

Snowflake Keypair Test Connection

CheckWhat it proves
configurationThe fields needed for the chosen authentication type are filled in
private keyThe key was read, decrypted if encrypted, and successfully signed a token. Skipped for token authentication.
streaming endpointSnowflake answered an authenticated request - so the host is reachable and the credential is accepted

Info

Test Connection proves you can reach Snowflake as this user. It does not open a channel and does not touch your database, schema or table, so it cannot tell you whether the table exists or whether the mapping matches it.

Column mapping

Sources

Each column takes a source, and that source - with the column's format - is what actually fills the row.

SourceFills the column with
Tag PropertyValue, Timestamp, Tag Name, Tag Path, Group Path, Quality, Quality Severity, Data Type, or any named custom tag property
HierarchyAn ISA-95 level, resolved from the groups enclosing the tag
ConstantA fixed value
System TimestampThe engine clock at row build. Publishing both this and the tag timestamp makes latency measurable.
DB TimestampThe column is omitted from the row entirely, so Snowflake's own DEFAULT CURRENT_TIMESTAMP() fires. Sending a null instead would override the default.
UUIDA fresh identifier per row, hyphenated or compact
Pipe ID / Channel ID / Stream OffsetIngestion metadata, filled in by the driver
Null / IgnoreThe column is omitted from the row

The ISA-95 levels available are Enterprise, Site, Site ID, Area, Work Center, Work Center Type, Work Unit, Work Unit Type, Work Unit ID, Equipment Module, Equipment Module ID, Control Module and Control Module ID.

Formats

Timestamp columns take ISO 8601, Unix seconds, Unix milliseconds, ticks, or a custom .NET format string. Value columns take as-is, force to string, parse as numeric, round to integer, true/false, 0/1, or a custom pair of boolean words. Timestamps are sent as UTC.

Info

The Snowflake type dropdown does not change what is sent. It drives the generated CREATE TABLE and nothing else. Changing a column's type does not change its value; changing its tag property does.

Note also that Tag Name returns the last two components of the tag path. On a two-level tag it is identical to Tag Path.

Presets

Two presets are built in, served from the engine so that the editor and the driver cannot hold different ideas of what they mean.

Default - four columns matching the table above:

ColumnTypeSource
idSTRINGTag Property → Tag Path
valueVARIANTTag Property → Value, as-is
qualityBOOLEANTag Property → Quality
timestampTIMESTAMP_NTZTag Property → Timestamp, ISO 8601

The identifier column carries the full tag path, not the short name: names are not unique across groups, and using one as a row key silently merges different tags.

ISA-95 Lite - 24 flattened columns: timestamp, namespace path, tag name, group path, all thirteen ISA-95 levels, three typed value columns, data type, quality, units and source protocol. The hierarchy is flattened one column per level because Snowflake columns are flat and a dotted column name would have to be quoted forever after. The typed value columns (value_double, value_string, value_boolean) are split rather than sharing one VARIANT because Snowflake sub-columnarizes a VARIANT only along paths that are never null.

A preset row is byte for byte an ordinary row. Applying a preset is an editor action, not a mode - afterwards you can edit, add and remove columns freely. Clearing the mapping means no columns, not "fall back to Default".

Ingestion metadata columns

+ Metadata Columns adds three entries whose name, type and source are locked in the editor.

ColumnTypeMeaning
PIPE_IDSTRINGWhich pipe produced the row
CHANNEL_IDSTRINGWhich channel - that is, which engine and driver interface
STREAM_OFFSETBIGINTThe row's position in that channel's ordered sequence

Snowflake recommends these on any streaming table, and they are what makes gap detection possible in SQL:

SELECT STREAM_OFFSET,
       LAG(STREAM_OFFSET) OVER (PARTITION BY PIPE_ID, CHANNEL_ID
                                ORDER BY STREAM_OFFSET) AS previous_offset
FROM   <db>.<schema>.<table>
QUALIFY STREAM_OFFSET <> previous_offset + 1;

They are locked because that query names them literally, and STREAM_OFFSET has to stay numeric or previous_offset + 1 fails outright. The driver binds them by source rather than by name, so a mapping that arrived through a CSV import or a hand edit still works.

Important

Map CHANNEL_ID whenever you map STREAM_OFFSET. Offsets are only meaningful within a channel; with two engines writing to one table, offsets alone are indistinguishable and every row looks like a gap.

SQL View

SQL View shows the CREATE TABLE statement the mapping describes, generated by the engine, so that what you hand a DBA is the same statement the driver would have used itself.

Table creation

Create Table If Missing is off by default. Ticked, the driver creates the target table from the column mapping on connect if it is not there.

  • It needs CREATE TABLE on the schema - a privilege streaming alone does not require.
  • OAS never alters or drops an existing table. A table whose columns do not match the mapping is left exactly as it is, and reported by preflight.
  • If the table cannot be created the driver stops, reports the error and sends nothing.

Info

Turning it off does not stop the driver reading table metadata. One metadata read happens on connect either way, because preflight uses the same answer - only the create is gated on this switch. If the credential is refused that read, nothing breaks: preflight reports that it could not check, and streaming proceeds.

Store and Forward

Tick Enable Store and Forward. Rows that cannot be sent are written to disk and replayed when the connection returns, oldest first, always. Buffer files are plain UTF-8 NDJSON with a .sfb extension, in the directory set under Configure → Options → Store and Forward.

Last In First Out is deliberately not offered on Snowflake. Snowpipe Streaming is an ordered protocol - a channel's rows are identified by a monotonic offset - so replaying the newest file first would land recent rows ahead of older ones under offsets that say the opposite.

A buffered row carries no offset of its own. It takes one when it is finally sent, which is what makes it land after whatever Snowflake actually kept.

Validation and row errors

An append returning success means Snowflake accepted the batch, not that it kept it. Rows are validated asynchronously against the table, so a wrong column mapping streams happily and writes nothing at all. Two mechanisms close that hole, and they catch different faults.

FaultSnowflake's responseSeen by
A value that cannot convert to its column's typeRejected, counted, message returnedValidation
A column name in the mapping that is not in the tableSilently discarded, error count zero. The row lands with that column absent.Preflight only

Rejected rows cannot be resent. Fix the mapping or the table.

Preflight

On every connect - and again after any mapping change - the driver compares the mapped column names against the table's actual columns and reports the ones that are missing, by name. A mapping change does not reconnect the driver, so a connect-only check would leave the alarm latched after the operator fixed the very thing it complained about.

Preflight is advisory and never blocks a connect. Reading table metadata needs a privilege that streaming does not, so a least-privilege credential that streams perfectly well can be refused it. An unreadable answer is treated as "could not check", never as "the table has no columns". The comparison is case-insensitive, because Snowflake upper-cases unquoted identifiers, and it compares names only, never types.

Validation

Validation polls the channel's status and reports what Snowflake actually did with the rows.

PropertyDefaultNotes
Enable ValidationoffPoll continuously. This is the only setting on this driver that sends a repeating request to Snowflake for as long as the driver is enabled.
Validation Interval300 sSeconds between polls, per driver instance. 300 s is roughly 288 requests per day; 30 s is ten times as many, for detection nine minutes sooner.
On Row ErrorsRaise System ErrorLog Only - write to the driver log. Raise System Error - raise an OAS system error carrying Snowflake's own message. Raise And Set Comm Bad - also fail the interface, which triggers Store and Forward.

Important

Enabling validation, and shortening its interval, directly multiplies how often the driver contacts Snowflake. How Snowflake meters and prices its services is set by Snowflake and can change. Review your agreement and confirm the cost with Snowflake before enabling this - particularly at a short interval, or across many drivers.

A one-shot check runs whether or not validation is enabled, about ten seconds after the first append of each connect. That is why a broken mapping is reported on the first attempt rather than never. It honours the On Row Errors setting even though that field is hidden while validation is off.

Five optional metric tags can be written on each poll:

TagValue
Rows InsertedRows Snowflake has committed for this channel
Row Error CountRows Snowflake has rejected. Alarm on this to be notified of a schema mismatch.
Last Error MessageThe most recent message from Snowflake
Processing LatencyAverage time Snowflake takes to process rows, in milliseconds
Last Committed OffsetThe last offset token Snowflake has committed

The counters are cumulative for the life of the channel, and the channel outlives the driver. The driver therefore measures errors from the moment it connects, so old rejections are not re-raised on every enable. A count that has gone backwards means a new channel.

Delivery guarantees

The channel carries the memory of what has been committed, so the driver does not delete its channel when it stops. It drops a channel only when abandoning its identity - a change of account, host, credential, database, schema, table, pipe, channel name, compression or request timeout - because that channel then names something it will never write to again.

Verify delivery with both checks together, since a duplicate and a loss cancel out in a gap count alone:

SELECT COUNT(*)                      AS rows_kept,
       COUNT(DISTINCT STREAM_OFFSET) AS distinct_offsets,
       MIN(STREAM_OFFSET)            AS first_offset,
       MAX(STREAM_OFFSET)            AS last_offset
FROM   <db>.<schema>.<table>
WHERE  CHANNEL_ID = '<channel>';

rows_kept equal to distinct_offsets, and last_offset - first_offset + 1 equal to both, is the proof. Observed commit latency is typically 5 to 7 seconds.

Operating the driver

Comm status. The usual Comm Bad, Comm Good and Comm Buffering driver tags behave as they do on every driver, so alarms need no new configuration.

System errors are latched per category and clear themselves when the condition goes away. Licensing, configuration problems, preflight mismatches and row rejections each report with the driver name, the target table and, where Snowflake supplied one, its own message.

Logging is opt-in. Tick Configure → Options → System Logging → Log Snowflake Communications to record the driver's activity to Log/OASTransactions-Driver-<name>-<date>.txt. It is off by default, so turn it on before trying to diagnose anything from the log.

One line in that log is worth knowing about. When the resolved column mapping changes, the driver writes:

Snowflake rows will be built from N mapped columns: ...

That is the receipt proving a mapping edit actually reached the running engine. It is written only when the mapping changes, so its absence after an edit means the edit did not arrive.

Troubleshooting

SymptomCause
Driver never connects, no Snowflake activity at allCheck the license first. An unlicensed driver is refused before any configuration is examined.
401 on connect, credentials look rightThe public key is not registered against this user, the account identifier is the legacy locator rather than the URL subdomain, or the host clock is fast enough that the token looks issued in the future. Verify the fingerprint before anything else.
Authentication worked yesterday, fails todayA Programmatic Access Token expired.
The key file will not loadCheck the first line. -----BEGIN RSA PRIVATE KEY----- with Proc-Type: 4,ENCRYPTED beneath it is the one unsupported key format. Also check the service account can read the file.
Good comms, no rows in the tableAlmost always the tag selection or the mapping. Check the driver is not reporting no tags are selected, then look for a preflight system error naming columns that are not in the table.
Rows arrive, one column is always emptyThat column name is not in the table. Snowflake discards the unknown key silently with an error count of zero, so only preflight sees it. Fix the mapping or add the column.
Table not found or not authorizedThe table does not exist, or the role lacks INSERT on it. Snowflake does not distinguish these.
Rejections reported, message names a typeA value cannot convert to the column's type. Check that column's Tag Property and format - not its Snowflake type, which affects only DDL.
STREAM_OFFSET restarted at zeroThe channel was dropped. Something in the channel identity changed - including Compression or Request Timeout - or two engines are using the same channel name against one pipe.
Test Connection succeeds, the driver does notTest Connection checks credentials and reachability only. It does not open a channel and never touches your database, schema or table.
A mapping edit seems to have no effectTurn on Log Snowflake Communications and look for the Snowflake rows will be built from N mapped columns line. No line means the edit did not reach the engine.
The driver log is emptyLogging is off by default. Tick Log Snowflake Communications.

Limits and caveats

  • Write only. The driver never reads from Snowflake into a tag.
  • Flat rows. Snowflake columns are flat and there is no nested output. Use a VARIANT column if you need structure inside one field.
  • No second target. An outage is ridden out by Store and Forward, not by streaming to a different table. A deployment with genuine multi-region Snowflake uses Snowflake's own Client Redirect, which needs Account Host Override, not a second target here.
  • Idle channels. Snowflake decides how long an idle streaming channel is retained, and can change that. The driver reopens and resumes from the committed offset, so an idle period costs nothing - but no claim is made about how long a channel survives untouched.
  • Two engines, one channel name. They will disconnect each other.
  • No account browsing. Database, Schema and Table are text fields, by design.
  • No role selection. The driver uses the user's default role.
  • Credential storage. The private key and any access token are stored in the driver configuration alongside every other driver property, and travel over the configuration API. That API should be on TLS. Encrypting the private key adds little when the key is pasted into the configuration, because the passphrase sits beside it; it is worth doing when the key lives in an external file.