Skip to main content

Snowflake ExecModule

Overview

SnowflakeModule connects ValkyrAI workflows to the Snowflake SQL API through the native map I/O ExecModule ABI. Workflow Studio discovers it as SnowflakeModule; the account identifier and bearer token are resolved only from a bound encrypted IntegrationAccount.

The initial connector covers warehouse discovery, parameterized read queries, confirmed single-statement SQL, bounded row insert/update operations, and statement status, partition, and cancellation operations. It normalizes Snowflake row arrays by their returned column names, caps responses, constructs only a Snowflake account host, and never retries an ambiguous mutation automatically.

Usage

  1. Create a least-privilege Snowflake service user and role with access only to the required warehouse, database, schema, and objects.
  2. Configure OAuth, key-pair JWT, or a role-restricted programmatic access token (PAT).
  3. Store the Snowflake account identifier in IntegrationAccount.accountId and the bearer token in the encrypted apiKey SecureField.
  4. Set the account to READY, bind it through ExecModuleConfig.authConfig.integrationAccount, and select the matching tokenType.
  5. Prefer the typed discovery, query, insert, and update operations. Use execute_statement only for a deliberate single DDL/DML statement.
  6. Supply a caller-owned UUID requestId and confirmWrite: true for every mutation.

Workflow input cannot provide credentials, an arbitrary hostname, an authorization header, or multiple SQL statements.

Inputs

NameTypeRequirementDefaultDescription and constraints
operationstringRequiredNoneOne of the ten documented operations.
tokenTypestringRequiredPROGRAMMATIC_ACCESS_TOKENOAUTH, KEYPAIR_JWT, or PROGRAMMATIC_ACCESS_TOKEN.
database / schema / warehouse / rolestringOptional contextAccount defaultsCase-sensitive Snowflake identifiers, up to 255 characters.
statementstringQuery/statement operationsNoneOne SQL statement, maximum 100,000 characters. Semicolon-separated statements are rejected.
bindingsarrayOptional query bindingsNoneUp to 1,000 {type,value} objects. Values must be JSON scalars.
tablestringRow/describe operationsNoneValid unquoted Snowflake identifier. Database/schema context is applied separately.
rowsarrayinsert_rowsNone1–500 objects with identical columns and scalar values.
valuesobjectupdate_rowsNoneNon-empty changed-column map, at most 50 columns.
whereobjectupdate_rowsNoneRequired equality predicates, at most 20 columns; prevents an unbounded update.
statementHandleUUID stringStatus/cancelNoneSnowflake statement handle.
partitionintegerOptional status read0Result partition from 0 through 10,000.
requestIdUUID stringRequired writesGenerated for readsCaller-owned Snowflake request-deduplication identifier.
asyncbooleanOptional submission modefalseReturns a pending statement receipt when accepted asynchronously.
statementTimeoutSecondsintegerOptional60Snowflake execution timeout from 1 through 3,600 seconds.
maxRowsintegerOptional1000Maximum normalized rows from one result partition, up to 10,000.
confirmWrite / confirmCancelbooleanMutation guardfalseExplicit acknowledgement for writes or statement cancellation.

Supported binding types are FIXED, REAL, DECFLOAT, TEXT, BINARY, BOOLEAN, DATE, TIME, TIMESTAMP_TZ, TIMESTAMP_LTZ, and TIMESTAMP_NTZ. Snowflake SQL API binding values are serialized as strings.

Outputs

NameTypeWhen presentDescription
statusstringAlwayssuccess, pending, or error.
operationstringAlwaysNormalized operation.
httpStatus / attemptsintegerProvider requestProvider status and total attempts.
items / countarray / integerResult-set successRows mapped to returned Snowflake column names.
dataobjectReceipt/non-row successSanitized provider response.
statementHandleUUID stringProvider returns itHandle for status, partition, or cancellation operations.
hasMore / nextPartitionboolean / integerPartitioned queryBounded continuation state.
errorobjectFailureSafe {code,message,httpStatus?,retryable} details.

Tokens and authorization values are redacted from errors, outputs, and workflow events.

IntegrationAccount Requirements

SettingRequirement
ProviderSnowflake account with the SQL API reachable through its account hostname
accountNameHuman-readable automation identity
accountIdSnowflake account identifier, for example myorg-myaccount
apiKeyEncrypted SecureField containing an OAuth token, key-pair JWT, or PAT
statusExactly READY

Use a role-restricted PAT or short-lived OAuth/key-pair JWT and a network policy that permits the ValkyrAI execution environment. The selected role needs only the warehouse USAGE, database/schema USAGE, and object privileges required by the chosen operations. Token issuance and rotation remain IntegrationAccount lifecycle responsibilities.

Configuration

{
"version": "1.0.0",
"authConfig": {
"authStrategy": 1,
"integrationAccount": "integration-account:snowflake-analytics"
},
"retryPolicy": {
"maxAttempts": 3,
"backoffStrategy": "EXPONENTIAL",
"initialDelayMs": 1000,
"maxDelayMs": 60000
},
"payloadConfig": {
"parameters": "{\"operation\":\"execute_query\",\"tokenType\":\"PROGRAMMATIC_ACCESS_TOKEN\",\"database\":\"ANALYTICS\",\"schema\":\"PUBLIC\",\"warehouse\":\"COMPUTE_WH\"}"
}
}

The integration-account reference is symbolic. Persisted workflows use the generated relationship and never plaintext tokens.

Operations

OperationSnowflake behaviorSide effect
execute_queryRuns one SELECT, SHOW, DESCRIBE, DESC, or EXPLAIN statement with optional bindings.Read-only; conservative retries.
execute_statementRuns one caller-supplied DDL/DML statement after confirmation.Write/DDL; single attempt.
insert_rowsBuilds one quoted parameterized INSERT for 1–500 same-shape rows.Write; single attempt.
update_rowsBuilds one quoted parameterized UPDATE with required equality predicates.Write; single attempt.
list_databasesExecutes fixed SHOW DATABASES.Read-only.
list_schemasExecutes fixed SHOW SCHEMAS, optionally in a database.Read-only.
list_tablesExecutes fixed SHOW TABLES, optionally in a database/schema.Read-only.
describe_tableExecutes a quoted DESCRIBE TABLE.Read-only.
get_statementGets statement status or one result partition by UUID.Read-only.
cancel_statementCancels a statement UUID after explicit confirmation.Control mutation; single attempt.

Errors and Failure Modes

CodeTypical causeRetryableResolution
VALIDATION_ERRORMissing credential/context, invalid identifier/UUID/binding, multiple statements, unsafe read SQL, absent predicate, or missing confirmation.NoCorrect the named input; no request was sent.
UNSUPPORTED_OPERATIONUnknown operation.NoSelect a documented operation.
INTEGRATION_ACCOUNT_REQUIREDNo bound account.NoBind a Snowflake IntegrationAccount.
INTEGRATION_ACCOUNT_NOT_READYAccount is not READY.NoRepair or reconnect the account.
SNOWFLAKE_HTTP_400 / 422Invalid SQL, binding, context, or provider constraint.NoCorrect the statement or typed inputs.
SNOWFLAKE_HTTP_401 / 403Invalid token, network policy, role, or privilege.NoRotate credentials or grant minimum required access.
SNOWFLAKE_HTTP_429 / 5xxConcurrency/rate limit or transient provider failure.Reads onlyRetry a read; reconcile a write by request ID/handle first.
NETWORK_ERRORTimeout, DNS, TLS, or connectivity failure.Reads onlyVerify connectivity; never blindly repeat an ambiguous mutation.
RESPONSE_TOO_LARGEResponse exceeded 10 MiB.NoNarrow the query or retrieve smaller partitions.

Example

Query qualified accounts with a bound value:

{
"operation": "execute_query",
"database": "ANALYTICS",
"schema": "PUBLIC",
"warehouse": "COMPUTE_WH",
"statement": "SELECT ID, NAME FROM ACCOUNTS WHERE SCORE >= ?",
"bindings": [
{"type": "FIXED", "value": "80"}
],
"maxRows": 100
}

Expected result:

{
"status": "success",
"operation": "execute_query",
"httpStatus": 200,
"count": 2,
"items": [
{"ID": "42", "NAME": "Northstar"},
{"ID": "77", "NAME": "Valkyr"}
],
"hasMore": false,
"attempts": 1
}

Notes

  • Pagination: Snowflake determines result partitions. The initial/status response exposes partition metadata; resume with get_statement and partition. This version returns one bounded partition per operation and never follows provider-supplied absolute URLs.
  • Rate limits: read-only requests may retry HTTP 408, 429, 500, 502, 503, and 504 with bounded exponential backoff while honoring integer or HTTP-date Retry-After. execute_statement, inserts, updates, and cancellation are always single-attempt.
  • API limits: request bodies are capped at 1 MiB, responses at 10 MiB, inserts at 500 rows, bindings at 1,000, and normalized output at 10,000 rows per partition.
  • Idempotency: every mutation requires a caller-owned UUID requestId. Snowflake uses it for request reconciliation, but a timeout is still ambiguous; inspect statement history/status before manual retry.
  • Destructive behavior: execute_statement can perform DDL or DML and therefore requires confirmWrite. This version has no typed delete, truncate, drop, user, role, grant, warehouse, task, stream, or pipe mutation.
  • SQL safety: use bind variables for all values. Identifiers are validated and quoted by typed operations. execute_query is prefix-allowlisted and rejects multiple statements; it is not a substitute for provider-side least privilege.
  • Authentication: OAuth, key-pair JWT, and PAT bearer tokens are supported. Password authentication and workflow-supplied tokens are intentionally unsupported.
  • External verification: local tests verify validation, request construction, fixed-host routing, bindings, response mapping, retries, redaction, and metadata discovery. Live Snowflake authentication, network policies, privileges, query execution, partition compression, and warehouse behavior require separately authorized provider credentials and are not exercised in repository tests.
  • Deferred operations: bulk array binding, staged file load/unload, PUT/GET, multi-statement transactions, stored procedure result sets, Arrow results, automatic partition fan-out, query history, and administrative object lifecycle.
  • Functional references: n8n Snowflake node source, Snowflake SQL API reference, and Snowflake authentication.