Export ignores /p:VerifyExtraction: bacpac exports cleanly from the same model Extract rejects with SQL71501
- Dominant language
- C#
- Stars
- 460
- Forks
- 29
- Avg merge
- 4d 9h
- Merged PRs (30d)
- 7
Description
- **SqlPackage or DacFx Version:** SqlPackage 162.1.172.1
- **.NET Framework (Windows-only) or .NET Core:** .NET Core
- **Environment (local platform and source/target platforms):** linux-x64 client; source and target are Azure SQL Database (compatibility level 170)
### Summary
`VerifyExtraction` is documented under **Properties specific to the Export action** as `(BOOLEAN 'True')` — *"Specifies whether the extracted schema model should be verified. If set to true, schema validation rules are run on the dacpac or bacpac."*
In practice it has no observable effect on `/a:Export`. A database whose model contains an unresolved reference exports to a `.bacpac` with exit code 0, while `/a:Extract /p:VerifyExtraction=True` against the **same database** fails with `SQL71501`. The `model.xml` inside the resulting `.bacpac` and `.dacpac` is **byte-identical**, so both actions verify the same model and reach different conclusions.
The documented defaults are also inverted between the two actions — Extract defaults `False`, Export defaults `True` — so the action that defaults verification *on* is the one that appears not to verify.
**Steps to Reproduce:**
1. Create a schema with a procedure reference that is then broken. SQL Server permits this; the procedure survives.
```sql
CREATE TABLE dbo.Processes (
Id INT NOT NULL PRIMARY KEY,
Name NVARCHAR(200) NOT NULL,
HasInvalidTransientData BIT NOT NULL CONSTRAINT DF_P DEFAULT(0)
);
GO
CREATE PROCEDURE dbo.PlanMigration AS
BEGIN
SELECT p.Id, p.Name
FROM dbo.Processes AS p
WHERE p.HasInvalidTransientData = 1;
END
GO
ALTER TABLE dbo.Processes DROP CONSTRAINT DF_P;
ALTER TABLE dbo.Processes DROP COLUMN HasInvalidTransientData;
```
2. Run each of the following against that database:
| Command | Exit | Result |
| --- | --- | --- |
| `/a:Extract /p:VerifyExtraction=True` | 1 | `SQL71501 ... [dbo].[PlanMigration] has an unresolved reference to object [dbo].[Processes].[HasInvalidTransientData]` |
| `/a:Extract /p:VerifyExtraction=False` | 0 | dacpac written |
| `/a:Export` (default, i.e. `True`) | 0 | bacpac written |
| `/a:Export /p:VerifyExtraction=True` | 0 | bacpac written |
| `/a:Export /p:VerifyExtraction=False` | 0 | bacpac written |
3. Unzip all three packages and compare `model.xml`. They are byte-identical (md5 `86b3eb9e3b7cf993674d9dd66aa75506`), and each records the dangling reference the same way — resolved dependencies as ``, the broken one as a `PersistedResolvableAnnotation`:
```xml
```
`ExtractApplicationScopedObjectsOnly=false` makes no difference to the Extract failure, so model scoping is not the variable.
### Why it matters
To be clear about impact: **Import faithfully reproduces the source.** The restored database has the same procedures, the same bodies, the same data, and fails the same way — `Msg 207, Invalid column name` on execution — exactly as the source database already does. Nothing is corrupted, and for a portability artifact that fidelity is arguably the correct behaviour.
The problem is narrower, and is about the contract of the flag. A caller who explicitly sets `/p:VerifyExtraction=True` on Export, reads the documented description ("schema validation rules are run on the dacpac or bacpac"), and gets exit code 0 has no way to know the model still contains unresolved references. The identical model handed to Extract with the identical flag value is rejected. Any tooling that uses Export's exit code as a schema-soundness gate is therefore silently wrong.
For contrast, `Publish` of the equivalent dacpac fails loudly, because it scripts in dependency order and creates the table before the procedure:
```
Error SQL72014: ... Msg 207 ... Procedure PlanMigration, Line 7
Invalid column name 'HasInvalidTransientData'.
Updating database (Failed)
```
(That publish also leaves the target partially applied — table created, zero procedures, zero rows.)
**Did this occur in prior versions? If not - which version(s) did it work in?**
Not investigated — only reproduced on SqlPackage 162.1.172.1. I have not tested earlier versions, so I can't say whether this is a regression or long-standing behaviour.
### Ask
Please clarify which of these is intended:
1. Export **should** run reference-resolution validation and currently does not — a product bug; or
2. Export's verification deliberately excludes reference resolution, in which case the Export property table (and its wording shared with Extract, "schema validation rules are run on the dacpac or bacpac") is misleading and should say what Export actually checks.
Either way, the inverted defaults plus the shared description make it easy to assume a bacpac has been validated for referential integrity when it has not.
Contributor guide
Research direction
Start with the SqlPackage /a:Export and /a:Extract entry points and the VerifyExtraction property behavior described in the issue. Reproduce the unresolved-reference case using the supplied SQL script, then compare the Export and Extract validation paths and their documentation. Done means either Export validates references consistently or its documented scope and defaults clearly describe the behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- sql
- Domain
- databases
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100