> For the complete documentation index, see [llms.txt](https://v2.dataos.info/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://v2.dataos.info/references/v1/engine-guide/microsoft-fabric.md).

# Microsoft Fabric

The full technical reference for building and running a Vulcan Data Product on Microsoft Fabric Warehouse, covering connection, authentication, materialization, catalog management, and troubleshooting.

Microsoft Fabric Warehouse is a SaaS T-SQL data warehouse built on top of OneLake, with Entra-ID-only authentication and warehouse lifecycle managed through the Fabric REST API rather than classic DDL. Vulcan runs against the Fabric Warehouse SQL endpoint to manage transformations with version control and gated deployments. This page is the full manual: connection and authentication, how each model kind materializes, the catalog (warehouse) creation workaround, `ALTER TABLE` limitations, and the failure modes you hit in real projects.

### Engine characteristics

| Property            | Value                                                                |
| ------------------- | -------------------------------------------------------------------- |
| Engine adapter type | `fabric`                                                             |
| Model dialect       | `fabric`, a dedicated sqlglot dialect distinct from `tsql`           |
| Support level       | Community contribution with limited community support                |
| Connection endpoint | Fabric Warehouse SQL analytics endpoint                              |
| Compute             | No separate driver or executor cluster to size                       |
| Warehouse lifecycle | Fabric REST API manages asynchronous warehouse creation and deletion |
| Tested Vulcan image | `tmdcio/vulcan-fabric:0.228.1.26` on the Draco 1.38 series           |

{% hint style="info" %}
**Community-supported adapter**

The Fabric engine adapter is a community contribution. Treat production use accordingly: validate every model kind and workaround in this page against your own Fabric capacity before depending on it for critical workloads.
{% endhint %}

## When to use Fabric

Choose Fabric Warehouse when your organization already standardizes on Microsoft Fabric for its lakehouse/warehouse estate and you want a governed SQL endpoint over OneLake-backed data without provisioning separate infrastructure. Fabric Warehouse is not a general-purpose SQL Server: it has a deliberately restricted T-SQL surface (no indexes, no explicit transactions, limited `ALTER TABLE`), and warehouse-level lifecycle operations run through an asynchronous management API rather than synchronous DDL. Vulcan's Fabric adapter is a subclass of the MSSQL adapter and inherits its `MERGE`, bulk-load, and column-introspection logic, adjusted for what Fabric Warehouse actually supports.

{% hint style="info" %}
⚠️ **Warehouse only: no Lakehouse, OneLake, or other Fabric item types**

Vulcan's fabric adapter targets only the Fabric Warehouse SQL analytics endpoint. It does not support, and this page does not cover:

Fabric Lakehouse (the Delta/Parquet-over-OneLake item type): a different storage item with its own SQL endpoint and its own semantics; not created, read, or written by this adapter.\
OneLake direct access (ADLS-style file/folder access to the underlying storage): out of scope; the adapter only talks to the Warehouse's T-SQL endpoint, never to OneLake paths directly.\
Direct Lake mode (Power BI's semantic-model layer reading Delta tables straight from OneLake): a separate Fabric/Power BI feature, not something Vulcan configures or materializes into.\
Spark notebooks / Fabric Spark compute: a different Fabric engine entirely; for Spark-based lakehouse workloads use the Spark engine guide.\
Any other Fabric item type (KQL databases, Data Factory pipelines, Eventstreams, Data Activator, ML models/experiments, etc.): none of these are provisioned or read by the fabric adapter.

If a project needs any of the above, treat it as a separate Fabric integration outside Vulcan's fabric engine adapter.
{% endhint %}

This page covers the Fabric **Warehouse** SQL endpoint only. Fabric Lakehouse, Spark notebooks, OneLake direct access, and Direct Lake mode are separate Fabric surfaces not driven by this adapter; for lakehouse-style Spark workloads, use the [Spark engine guide](/references/v1/engine-guide/spark-1.md) instead.

## Supported model kinds

`FULL`, `SEED`, `VIEW`, `INCREMENTAL_BY_TIME_RANGE`, `INCREMENTAL_BY_UNIQUE_KEY`, `INCREMENTAL_BY_PARTITION`, `INCREMENTAL_UNMANAGED`, `SCD_TYPE_2`, `SCD_TYPE_2_BY_TIME`, `SCD_TYPE_2_BY_COLUMN`, and `EMBEDDED` are inherited from the base MSSQL adapter. `MANAGED` models and table cloning are not supported.

## Connection options

Connect Vulcan to Fabric Warehouse directly, with the credentials supplied through a Secret's projection. This is the only supported connection path for Fabric: a Depot cannot be used. The connection itself uses Microsoft Entra service-principal authentication.

Set connection details under `gateways.<name>.connection` in `config.yaml`, and project the Secret's values into the environment variables the gateway reads.

### Authentication methods

Fabric Warehouse only accepts Microsoft Entra ID authentication. There is no SQL-login/password path.

* **Service principal (recommended for the Vulcan gateway):** register an Entra app registration and grant it Fabric workspace access. Set `user` to the client ID, `password` to the client secret, plus `tenant_id` and `workspace_id`.
* Set `driver: pyodbc` and `odbc_properties: {authentication: ActiveDirectoryServicePrincipal}`. Install the `fabric` extra with `pip install "vulcan-0.228.1.28-py3-none-any.whl[[fabric]"`.
* Always inject the client secret from an environment variable: `password: {{ env_var('FABRIC_CLIENT_SECRET') }}`.

Interactive browser authentication suits local exploration. Do not use it for production gateways.

### Properties in `config.yaml`

In `config.yaml`, set these under `gateways.<name>.connection`.

| Option            | Description                                                                                                                                                  | Type          | Required |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------- | -------- |
| `type`            | Engine type name. Must be `fabric`.                                                                                                                          | string        | Yes      |
| `host`            | The hostname of the Fabric Warehouse SQL analytics endpoint.                                                                                                 | string        | Yes      |
| `user`            | The client ID (application ID) for authentication.                                                                                                           | string        | No       |
| `password`        | The client secret for authentication.                                                                                                                        | string        | No       |
| `port`            | The port number. Default `1433`.                                                                                                                             | int           | No       |
| `database`        | The target warehouse name.                                                                                                                                   | string        | No       |
| `charset`         | The character set used for the connection.                                                                                                                   | string        | No       |
| `timeout`         | Query timeout in seconds. Default: no timeout.                                                                                                               | int           | No       |
| `login_timeout`   | Seconds to wait for connection and login (default 60).                                                                                                       | int           | No       |
| `appname`         | The application name for the connection.                                                                                                                     | string        | No       |
| `conn_properties` | List of raw connection properties.                                                                                                                           | list\[string] | No       |
| `autocommit`      | Enable autocommit mode. Fabric Warehouse defaults this to `true` because the adapter does not rely on explicit transactions.                                 | bool          | No       |
| `driver`          | Driver used for the connection. Fabric only supports `pyodbc`.                                                                                               | string        | No       |
| `driver_name`     | ODBC driver name, for example `ODBC Driver 18 for SQL Server`.                                                                                               | string        | No       |
| `odbc_properties` | ODBC connection properties, for example `authentication: ActiveDirectoryServicePrincipal`.                                                                   | dict          | No       |
| `tenant_id`       | The Azure / Entra tenant UUID.                                                                                                                               | string        | **Yes**  |
| `workspace_id`    | The Fabric workspace UUID. Retrieve it by running `notebookutils.runtime.context.get("currentWorkspaceId")` in a Python notebook, or from the workspace URL. | string        | **Yes**  |

## Fabric-side permissions and grants

Three roles are required, each with a distinct scope.

| Role                     | Scope                                    | Required access                                                                                                                              |
| ------------------------ | ---------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| Admin role               | Fabric workspace admin or capacity admin | Creates the workspace, assigns capacity, and grants workspace roles.                                                                         |
| Vulcan service principal | Entra app registration used by Vulcan    | **Contributor** or higher workspace role. Requires `db_datareader`/`db_datawriter`-equivalent SQL endpoint access for model materialization. |
| Consumer role            | BI users and endpoint consumers          | **Viewer** workspace role and SQL endpoint read access.                                                                                      |

Grant the service principal a workspace role in the Fabric portal (Workspace settings → Manage access → Add people or groups → select the app registration → Contributor), then verify SQL-level access:

```sql
SELECT name, type_desc FROM sys.database_principals WHERE name = '<service-principal-name>';
```

`connection.database` (the warehouse name) must exist before `vulcan plan`, unless the Vulcan resource is configured to create it. In that case, the adapter drives creation through the Fabric REST API. See [Catalog (warehouse) lifecycle](#catalog-warehouse-lifecycle).

## DataOS permissions

These permissions must be provisioned before you create and deploy Data Products.

| Permission                                                  | What it Allows                                                                                                      | Granted By                                                           |
| ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| Tenant Access                                               | Build and manage Data Products within your tenant.                                                                  | Tenant Admin                                                         |
| `roles:id:data-dev` (or your tenant's equivalent role tag)  | Create and apply Vulcan resources. Verify with `dataos-ctl user get` (check the TAGS column).                       | Tenant Admin                                                         |
| Can Use (Compute, Secrets)                                  | Allows you to actually use Compute and Secrets. Resource access is deny-by-default: a role tag alone is not enough. | Tenant Admin or Data Admin                                           |
| git-sync Secret                                             | Allows Vulcan to pull model code from Git using a Secret. Request a git-sync Secret, not raw Git credentials.       | Tenant Admin, Data Admin, or the Secret owner (with Can Use granted) |
| Fabric workspace Contributor role for the service principal | Required in addition to the DataOS-level grants; Fabric authorization is separate from DataOS authorization.        | Fabric workspace admin                                               |

Confirm you can use the service-principal Secret before you start. If it is missing, request it, along with `Can Use` on it, from your operator.

## Gateway config examples

### Direct connection with a service principal

```yaml
gateways:
  fabric:
    connection:
      type: fabric
      host: xxxxx.datawarehouse.fabric.microsoft.com
      driver: pyodbc
      driver_name: "ODBC Driver 18 for SQL Server"
      odbc_properties:
        authentication: ActiveDirectoryServicePrincipal
      user: "{{ env_var('FABRIC_CLIENT_ID') }}"
      password: "{{ env_var('FABRIC_CLIENT_SECRET') }}"
      tenant_id: "{{ env_var('FABRIC_TENANT_ID') }}"
      workspace_id: "{{ env_var('FABRIC_WORKSPACE_ID') }}"
      database: warehouse
```

Validate the connection:

```bash
vulcan --log-to-stdout plan
```

### Supplying the credentials from a Secret

In production, keep the service-principal values in a DataOS Secret and project them into the workload, so the gateway resolves `FABRIC_CLIENT_ID`, `FABRIC_CLIENT_SECRET`, `FABRIC_TENANT_ID`, and `FABRIC_WORKSPACE_ID` from the environment rather than from anything committed to the repository. The gateway config stays exactly as shown above.

Apply the Secret, the Git Secret, the project configuration, and the Vulcan resource in that order. See [Production deployment](#production-deployment) for the required resources.

## No local Docker setup

Fabric Warehouse is a SaaS-only service with no self-hosted or emulated equivalent, so there is no local Docker stack for this engine, unlike Postgres or Spark. Local development connects to a real (typically dev-tier) Fabric workspace. Keep a lightweight dev warehouse per developer or team, and rely on `vulcan plan` dry-runs plus unit tests (which run against DuckDB locally, not Fabric) to iterate quickly before touching the shared warehouse.

## Production deployment

{% stepper %}
{% step %}

### `secret-fabric-serviceprincipal.yaml`

Stores the Entra client ID, client secret, tenant ID, and workspace ID.
{% endstep %}

{% step %}

### `secret-git-sync.yaml`

Repo credentials for git-sync.
{% endstep %}

{% step %}

### `config.yaml`

Gateway points at the warehouse (`type: fabric`), reading the service-principal values from the projected Secret.
{% endstep %}

{% step %}

### `workspace-deploy.yaml`

Workflow plus API; references `engine: fabric`, the Secret, and the repo.
{% endstep %}
{% endstepper %}

## Materialization behavior per model kind

SQL models compile to the `fabric` dialect and execute against the warehouse SQL endpoint. Because Fabric Warehouse has no native transactions and a restricted T-SQL surface, several kinds materialize differently than on generic MSSQL.

| Model kind                            | Compiles to                                                                         | Notes                                                                       |
| ------------------------------------- | ----------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
| SEED                                  | Staged bulk load via a temp table, then `INSERT ... SELECT`                         | Inherited from the MSSQL adapter's `bulk_copy` path.                        |
| FULL                                  | `SELECT * INTO` on first run; subsequent runs replace content via delete-and-insert | No atomic `CREATE OR REPLACE TABLE`.                                        |
| VIEW                                  | `CREATE OR ALTER VIEW`                                                              | Always a full rewrite.                                                      |
| INCREMENTAL\_BY\_TIME\_RANGE          | `DELETE` by `time_column` window, then `INSERT`                                     | Uses the DELETE\_INSERT strategy (see below), not MERGE.                    |
| INCREMENTAL\_BY\_UNIQUE\_KEY          | Native `MERGE INTO ... USING ... ON <key>`                                          | Same MERGE logic as MSSQL, including the `mssql_merge_exists` optimization. |
| INCREMENTAL\_BY\_PARTITION            | `DELETE` by partition key, then `INSERT`                                            | Generic delete-plus-insert fallback.                                        |
| INCREMENTAL\_UNMANAGED                | Append-only pattern                                                                 | Vulcan does not manage updates or deletes.                                  |
| SCD\_TYPE\_2 / SCD\_TYPE\_2\_BY\_TIME | History table with validity windows tracked by time                                 |                                                                             |
| SCD\_TYPE\_2\_BY\_COLUMN              | History table with validity windows tracked by checked columns                      |                                                                             |
| EMBEDDED                              | Not materialized                                                                    | Inlined into downstream models.                                             |

### Insert-overwrite strategy: DELETE\_INSERT, not MERGE

Unlike generic MSSQL, where the default insert-overwrite strategy is `MERGE`, the Fabric adapter overrides this to `DELETE_INSERT`. Time-range and partition overwrites compile to an explicit `DELETE FROM ... WHERE ...` followed by `INSERT INTO ... SELECT ...`, executed as separate statements rather than a single `MERGE`. Since Fabric Warehouse does not support explicit transactions (`SUPPORTS_TRANSACTIONS` is off for this adapter), the delete and insert are not wrapped in a rollback-able transaction the way they might be elsewhere; plan reruns and `concurrencyPolicy: Forbid` matter more here than on engines with full transactional DDL.

### `INCREMENTAL_BY_UNIQUE_KEY` still uses MERGE

`INCREMENTAL_BY_UNIQUE_KEY` is the one kind that keeps the inherited MSSQL `MERGE INTO` path, including the `mssql_merge_exists` optimization described in the [MSSQL manual](/references/v1/engine-guide/sql-server.md#merge-and-the-mssql_merge_exists-optimization). The same column-type caveats apply (`GEOMETRY`, `XML`, `TEXT`, `NTEXT`, `IMAGE`, most user-defined types are not supported by the `EXCEPT`-based optimization); however, Fabric Warehouse's own type surface is already narrower than SQL Server's. Most of those types will not exist in a Fabric-native schema.

## Catalog (warehouse) lifecycle

Fabric Warehouse creation and deletion are not synchronous DDL statements. The adapter calls the Fabric REST API (`https://api.fabric.microsoft.com/v1/workspaces/{workspace_id}/warehouses`) using OAuth2 client-credentials (service principal) authentication against `login.microsoftonline.com`. Warehouse creation is asynchronous: Fabric returns a `202 Accepted` and the adapter polls the operation status with retries and exponential backoff until the warehouse is ready.

If you drop and immediately recreate a warehouse with the same name, Fabric can return an `ItemDisplayNameNotAvailableYet` error while the old name is still reserved during cleanup. The adapter waits and retries automatically, but if you are scripting warehouse teardown/recreation outside Vulcan, build in a similar wait-and-retry step rather than recreating immediately.

### Catalog switching has no session-persistent `USE`

Fabric Warehouse does not support `USE <database>` persisting across statements the way SQL Server does; each statement can run against its own session context. Because of this, the adapter does not attempt `USE` when switching the active catalog: it commits any pending work, closes the current connection, and opens a new connection directly against the target warehouse. If you write custom lifecycle SQL that assumes a persistent `USE` session (common in scripts ported from generic MSSQL), it will not behave the same way on Fabric. Always qualify objects with the warehouse name or rely on Vulcan's own catalog-switch handling rather than raw `USE` statements.

Since mid-2025, Fabric also validates that the `Database=` value in the connection string still exists at connection time and raises an authentication failure if it does not. Practically, this means dropping a warehouse that a live connection is still pointed at can surface as a misleading "authentication failed" error rather than an object-not-found error. Always close and reopen a connection after dropping its target warehouse.

## `ALTER TABLE` limitations and workaround

Fabric Warehouse has limited support for `ALTER TABLE`: it does not support directly changing a column's data type (`ALTER COLUMN ... TYPE`). When a schema change requires a column type change, the adapter runs a four-step workaround inside the same session:

{% stepper %}
{% step %}

### Add a temporary column

```sql
ALTER TABLE ... ADD <temp_column> <new_type>
```

{% endstep %}

{% step %}

### Cast existing values

```sql
UPDATE ... SET <temp_column> = CAST(<old_column> AS <new_type>)
```

{% endstep %}

{% step %}

### Drop the old column

```sql
ALTER TABLE ... DROP COLUMN <old_column>
```

{% endstep %}

{% step %}

### Rename the temporary column

```sql
EXEC sp_rename
```

Rename `<temp_column>` back to the original column name.
{% endstep %}
{% endstepper %}

Column additions that are not type changes execute as a direct `ALTER TABLE ... ADD` without the workaround. If you see a schema-migration step taking noticeably longer or touching more rows than expected, check whether it triggered this rewrite path. It is a full column rewrite, not a metadata-only operation, and its cost scales with table size.

## No native indexes on Fabric Warehouse

Fabric Warehouse does not support user-defined indexes the way SQL Server does; `CREATE INDEX` in guarded `post_statements` is a MSSQL-only pattern and is not available here. There is no `SUPPORTS_INDEXES` path for this adapter. Query performance on large tables depends on Fabric's own internal storage and statistics rather than explicit indexing, so the levers available on Postgres/MSSQL (add an index on a hot filter column) do not apply. Instead, favor partition-aligned filters, narrower `SELECT` lists, and pre-aggregated marts for expensive query shapes.

## Identifier casing and type surface

Fabric Warehouse's T-SQL surface is narrower than full SQL Server: some data types (notably `GEOMETRY`, `XML`, `TEXT`, `NTEXT`, `IMAGE`, and most user-defined types) either do not exist or are not fully supported. Use the standard Fabric-supported types (`INT`, `BIGINT`, `DECIMAL`, `VARCHAR(n)`, `NVARCHAR(n)`, `DATETIME2`, and similar) in model DDL. As with MSSQL, always declare an explicit length on `VARCHAR`/`NVARCHAR` columns.

## Lifecycle DDL

Wrap DDL in `pre_statements` / `post_statements` when it should run only during real execution, or a dry-run plan executes it:

```sql
@IF(
    @runtime_stage = 'evaluating',
    ALTER TABLE warehouse.gold.orders ADD ingested_at DATETIME2
)
```

Because Fabric has no explicit transaction support, be conservative with multi-statement lifecycle DDL. A failure partway through will not roll back earlier statements in the block.

## External source declarations

Declare non-owned source tables in `external_models.yaml` so linting and lineage resolve them. The physical table must exist only if a model actually selects from it.

## Semantic models and metrics

Use `{semantic_model.column}` braces for measure references and declare joins for multi-entity queries; cross-join-shaped semantic queries are one of the easiest ways to generate an expensive query on a warehouse with no user-tunable indexing. `COUNT(DISTINCT ...)` over wide tables is a primary cost driver; pre-aggregate into a mart rather than relying on an index, since indexes are not available here. Native constraints declared in Fabric Warehouse (`PRIMARY KEY`, `UNIQUE`) are informational only in some Fabric editions. Do not assume they are enforced at write time the way they are on SQL Server; keep Vulcan audits as the actual guardrail.

## Endpoints

Every deployed Data Product gets REST, GraphQL, and MySQL-wire endpoints, all pushing down to the same Fabric gateway. Large result sets are buffered before streaming; size `api.resource.limit.memory` for expected payloads, with 3 GiB a practical starting point for high-row responses.

## Metadata scanning and catalog

DataOS scans `INFORMATION_SCHEMA` and the subset of `sys.*` catalog views exposed by Fabric Warehouse. Lineage comes primarily from parsed model definitions and Vulcan's model graph, since Fabric's query-history surface for warehouse workloads is more limited than Snowflake's `ACCOUNT_USAGE`. Use a scanner service principal with the **Viewer** workspace role, separate from the Vulcan service principal used for `rw`.

Scanner cadence is commonly every 6 to 12 hours. If lineage is missing after `vulcan apply`, verify `external_models.yaml`, then wait for the next scan.

## Engine-native feature support

| Feature                               | How                                                      | Notes                                                           |
| ------------------------------------- | -------------------------------------------------------- | --------------------------------------------------------------- |
| Warehouse (catalog) creation/deletion | Fabric REST API, driven by the adapter                   | Asynchronous; the adapter polls until ready.                    |
| Schema                                | Referenced by model names                                | Created automatically when the service principal has privilege. |
| Regular / incremental table           | FULL and incremental models                              |                                                                 |
| View                                  | `kind VIEW`                                              | `CREATE OR ALTER VIEW`.                                         |
| SCD history                           | `SCD_TYPE_2_BY_TIME` / `SCD_TYPE_2_BY_COLUMN`            |                                                                 |
| Unique-key upsert                     | `INCREMENTAL_BY_UNIQUE_KEY`                              | Native `MERGE INTO`, same as MSSQL.                             |
| Time-range / partition overwrite      | `INCREMENTAL_BY_TIME_RANGE` / `INCREMENTAL_BY_PARTITION` | `DELETE` + `INSERT`, not `MERGE`.                               |
| Column type change                    | Guarded `ALTER TABLE`                                    | Four-step rewrite workaround; see above.                        |
| Indexes                               | Not supported                                            | No index DDL path on this adapter.                              |
| Explicit transactions                 | Not supported                                            | `SUPPORTS_TRANSACTIONS` is off.                                 |
| Materialized view                     | Not supported by this adapter                            |                                                                 |
| Table cloning                         | Not supported                                            |                                                                 |
| MANAGED model kind                    | Not supported                                            |                                                                 |

Boundaries: indexing, explicit multi-statement transactions, materialized views, table cloning, MANAGED models, and the Lakehouse/Spark/OneLake side of Fabric (a separate surface not driven by this adapter). Treat workspace capacity assignment, Fabric admin-portal settings, and cross-workspace sharing as Fabric admin boundaries.

## Operational boundaries

### Compute sizing

Fabric Warehouse compute is tied to the workspace's assigned Fabric capacity (an F-SKU or trial capacity), not a per-query warehouse you resize yourself the way you would on Snowflake. Size the assigned capacity for your workload's concurrency and data volume at the Fabric-admin level; Vulcan has no lever to resize Fabric capacity from the project config.

### Concurrency

Start with `concurrent_tasks: 2` for daily incrementals. Because there are no explicit transactions and the overwrite strategy is DELETE\_INSERT rather than MERGE for time-range/partition kinds, avoid overlapping runs against the same table. A second run's `DELETE` can race a first run's `INSERT` with no transactional isolation to fall back on. Use `concurrencyPolicy: Forbid` for every scheduled workflow on this engine.

### Scheduling and latency floor

Schedule after upstream lands, set `timezone: UTC`, set `endOn` 1 to 2 years out, and use `concurrencyPolicy: Forbid`. The latency floor includes: warehouse SQL endpoint connection setup (Entra token acquisition plus ODBC connect), no index-assisted point lookups (every filtered query is closer to a scan than it would be on an indexed MSSQL table), and asynchronous warehouse creation/drop latency (seconds to tens of seconds) if your workflow provisions warehouses dynamically.

## Performance reference

Because there is no user-tunable indexing, sizing conversations for Fabric center on query shape and capacity tier rather than index design. Track plan/run duration per model, semantic query wall time, and rows touched per incremental window. When concurrency or latency degrades, fix in order: remove cross-join-shaped queries, pre-aggregate high-cardinality `COUNT(DISTINCT ...)` measures into a mart, stagger schedules so DELETE\_INSERT-based incrementals never overlap on the same table, then escalate the Fabric capacity tier as a platform-level change. Reproduce measurements against your own workspace capacity before quoting them externally. Fabric capacity tiers behave differently from a dedicated SQL Server instance under load.

## Troubleshooting

### Failure modes

The errors you are most likely to hit, with cause and fix.

| Symptom                                                                    | Likely cause                                                                | Fix                                                                                                          |
| -------------------------------------------------------------------------- | --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| Authentication failed on connect                                           | Client secret expired, or `tenant_id`/`workspace_id` mismatched             | Rotate the secret; verify tenant and workspace UUIDs.                                                        |
| Authentication failed after a warehouse drop                               | Connection string still points at a `Database=` value that no longer exists | Close and reopen the connection against a valid warehouse.                                                   |
| `ItemDisplayNameNotAvailableYet`                                           | Warehouse recreated immediately after being dropped                         | Wait for cleanup to finish; the adapter retries automatically, but scripted flows should add a delay.        |
| Column type change appears slow / rewrites the whole table                 | Fabric has no direct `ALTER COLUMN` type change                             | Expected: the adapter performs a full column rewrite (add, cast, drop, rename). Size the change accordingly. |
| `CREATE INDEX` fails or is a no-op                                         | Fabric Warehouse does not support user indexes                              | Remove index DDL from `post_statements`; rely on query shape and pre-aggregation instead.                    |
| Incremental overwrite left the table in a partial state after a failed run | No explicit transaction wraps DELETE\_INSERT                                | Re-run the affected window; avoid overlapping schedules with `concurrencyPolicy: Forbid`.                    |
| `mssql_merge_exists` throws on `EXCEPT`                                    | Unsupported column type in the merge comparison                             | Disable the optimization for that table.                                                                     |
| `vulcan plan` runs DDL                                                     | Lifecycle DDL not guarded                                                   | Wrap in `@IF(@runtime_stage = 'evaluating', ...)`.                                                           |
| Endpoint OOM on large result                                               | API memory too low                                                          | Raise API memory and limit result size.                                                                      |
| Local Docker stack expected but unavailable                                | Fabric has no local/self-hosted equivalent                                  | Develop against a dedicated dev-tier Fabric workspace instead.                                               |

### Health-check queries

Run these queries to verify the current warehouse and service principal.

```sql
SELECT DB_NAME() AS current_warehouse, SUSER_SNAME() AS current_principal;

SELECT s.name AS schema_name, t.name AS table_name
FROM sys.tables t JOIN sys.schemas s ON t.schema_id = s.schema_id
ORDER BY s.name, t.name;
```

### Recovery procedures

Use these procedures to restore failed workflows and resolve operational interruptions.

| Situation                                    | Procedure                                                                                                                                                                                          |
| -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Incremental run failed mid-window            | Re-run; time-range and partition incrementals reprocess the affected window via `DELETE` + `INSERT`.                                                                                               |
| Warehouse creation stuck in progress         | Check the Fabric portal for the operation status; the adapter's polling has a bounded number of retries, after which it surfaces an error. Retry `vulcan apply` once the warehouse shows as ready. |
| Table dropped manually                       | `vulcan plan` detects and recreates; use a rebuild command if needed.                                                                                                                              |
| Column-type migration failed partway         | Inspect the table for a leftover temp column from the rewrite workaround; drop it manually and re-run the migration.                                                                               |
| Credentials leaked                           | Rotate the service principal's client secret in Entra ID; update `.env` / DataOS instance secret.                                                                                                  |
| Concurrent runs conflicted on the same table | Set `concurrencyPolicy: Forbid`; stagger heavy incremental models.                                                                                                                                 |

## Full implementation example

Use this complete Data Product as a production-shaped starting point.

{% file src="/files/bkkYina7q9s9ICfKiP4D" %}

## Related

* [MSSQL manual](/references/v1/engine-guide/sql-server.md) for the adapter this engine subclasses (grants, MERGE tuning, and general T-SQL behavior carry over except where this page calls out a difference).
* [Engine guide overview](/references/v1/engine-guide/engine-guide.md) for the cross-engine rules.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://v2.dataos.info/references/v1/engine-guide/microsoft-fabric.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
