# Failure modes seen in production

Each entry: what happens, why, how to detect it, how the plan prevents it, and the safe repair. HubSpot behaviours cited were checked on 2026-10-17.

## Data model and identity

Duplicate companies from an integration

- Why: companies created through the API, including third-party sync apps, are not deduplicated by Company domain name.
- Detect: groups of companies with the same primary domain where Record Source is an integration; counts rising after each sync run.
- Prevent: a unique-value property with the source account ID; the integration searches it before creating; unmatched records go to a review queue instead of being created.
- Repair: stop or narrow the writer first, then review candidates by source ID and history. Merge only approved pairs (merges are irreversible).

Shared-domain accounts merged by mistake

- Why: subsidiaries, operating units or a reseller's customers share a domain.
- Detect: one company with contacts from clearly separate customers; deals with different billing entities.
- Prevent: decide the account boundary before import; key companies on the internal account ID.

Automatic company association on a keyed portal

- Why: "Create and associate companies with contacts" is on while companies are keyed on a source account ID or synced from Salesforce. It creates a company per unknown email domain and, on a shared domain, attaches the contact to one company you cannot choose.
- Detect: companies with an empty source ID property (read Record Source and property history to see what created them); contacts on a shared domain associated to the wrong account; duplicate companies after Salesforce pairing.
- Prevent: turn the setting off (or exclude shared domains, up to 1,000) before any import, form launch or integration, and record it in `decisions.md`. Associate contacts by source ID in a multi-file import or the integration.
- Repair: stop the setting first, then fix associations by source ID; merge domain-only companies into keyed ones only per approved pair.

Numbered property sets

- Why: a one-to-many entity (workspaces, subscriptions) squeezed onto the company.
- Detect: properties named `*_1_*`, `*_2_*`; values missing for the fourth instance.
- Prevent: the property-versus-object rules; summaries on the company and detail in the warehouse when no one acts on instances.

Near-duplicate properties

- Why: each new integration creates its own field instead of using the register.
- Detect: several properties with similar labels and different writers (`plan`, `current_plan`, `stripe_plan`).
- Prevent: one writer per property in the register; new fields need a register row first.

## Lifecycle and stages

Lifecycle cannot be corrected by import

- Why: imports, forms, the API, workflows and the Salesforce integration only move lifecycle forward.
- Detect: rows reported as updated but lifecycle unchanged; customers sitting at Opportunity after churn handling.
- Prevent: a governed clear-then-set workflow and a correction reason property.

Lifecycle used for everything

- Why: subscription state, churn and follow-up crammed into lifecycle.
- Detect: custom lifecycle options like "Churned" or "Trial"; reports that cannot say who is a customer.
- Prevent: separate properties for subscription status and follow-up state.

Lead status and the leads object both in use

- Why: the leads object was activated without retiring Lead status.
- Detect: the same contact "working" in one and "new" in the other.
- Prevent: one owner field for follow-up state, recorded in `decisions.md`.

Required stage properties assumed to guard every writer

- Why: HubSpot documents conditional stage properties for users who create or move a record manually. Imports, integrations, workflows and API writes are not documented as blocked.
- Detect: deals in a stage with required properties empty; the per-stage view of missing properties is not empty.
- Prevent: test each writer against the stage; check the per-stage view daily during observation.

Stage IDs changed under an integration

- Why: a stage was recreated or a pipeline copied, so its internal ID changed.
- Detect: integration errors or deals landing in the default stage.
- Prevent: stage changes run as migrations; the register stores internal IDs.

## Import and marketing status

Unplanned marketing contact upgrade

- Why: exceeding the tier by one marketing contact upgrades the account until renewal; non-marketing changes wait for the update date. A HubSpot form with "Set new contacts as marketing contacts" on also converts existing non-marketing contacts who submit it, so an import kept non-marketing on purpose becomes billable one submission at a time.
- Detect: marketing contact count before and after each import, form launch or integration, and weekly during observation.
- Prevent: default non-marketing on imports and integrations; per-form switch reviewed against who submits that form; maximum cap set where appropriate; count checked against tier in the launch checklist.

Opt-outs lost in migration

- Why: contacts were moved without their opt-outs, unsubscribes and hard bounces from the old system, or an opt-out was cleared because a new source supplied the address.
- Detect: opted-out count in the source differs from HubSpot; complaints or unsubscribes from people who had already opted out.
- Prevent: load opt-outs and bounces before, or with, any marketing-status change; rehearse an unsubscribed and a hard-bounced contact; never clear an opt-out from a new source.
- Repair: stop sends to the affected group first, then restore the opt-outs from the old system's export with the privacy owner.

Historical import triggers live workflows

- Why: imported records meet the same triggers as new requests.
- Detect: enrolments of records in the batch shortly after it ran, found by the import tag or a static segment of the file's Record IDs; customers receiving prospect sequences. Record Source finds only records the import created, not ones it updated.
- Prevent: workflows off, or excluding the running batch by its tag, during imports; turn workflows on with future-only enrolment; for scheduled workflows add an exclusion, because existing matching records can enrol on the next scheduled run.

Workflow exclusion on Record Source drops real requests

- Why: a routing workflow excludes "Record Source is Import" to protect against the historical load. Record Source never changes, so every later request from an imported contact is excluded for good.
- Detect: demo or contact requests from imported contacts with no owner and no routing status.
- Prevent: exclude a batch by its tag only while it runs, and remove the exclusion when the batch is reconciled. Test an imported contact submitting the form after launch.

Fabricated acquisition source

- Why: someone stamps a guessed channel on imported records to fill a dashboard.
- Detect: a sudden block of identical source values with the import date.
- Prevent: legacy acquisition fields with an observed date; unknown stays unknown.

Bulk merge to clear duplicates

- Why: merging feels like cleanup; it cannot be undone, the survivor takes the most advanced lifecycle and the most marketable status, and records already in 250 merges cannot be merged again.
- Detect: merged record ID property populated on many records after a single session.
- Prevent: a review queue with an approver per pair.

## Forms and tracking

Two tracking codes on one page

- Why: an old agency portal's code left in a template; only the first code to load fires.
- Detect: two HubSpot script requests on a page with different portal IDs.

No history on imported contacts

- Why: page views attach only after a form submission or tracked marketing email click.
- Detect: imported contacts with empty page-view history.
- Prevent: set expectations; do not report attribution for that cohort.

Server-side form handler loses the visit

- Why: the HubSpot tracking cookie is not passed with the submission.
- Detect: form contacts from the custom handler with no source and no page views.
- Prevent: forward the cookie value with the submission, per the current Forms API docs.

UTMs lost before the form

- Why: hidden fields read only the current page URL; pre-populate for returning visitors can overwrite hidden values.
- Detect: high share of submissions with empty UTM fields from campaign traffic.

## Integrations

Salesforce first sync overwrites newer HubSpot values

- Why: on the first sync of a field with no sync history, the Salesforce value is the baseline.
- Detect: property history shows the integration writing an older value at pairing time.
- Prevent: decide per field which side is true before pairing; clean the losing side first.

Smart Transfer and the native integration together

- Why: they match records with different identifiers.
- Detect: duplicate records in both systems after enabling the integration.
- Prevent: turn off Smart Transfer sync connections before installing.

Inclusion segment treated as a security boundary

- Why: mapped fields can update Salesforce before the record joins the segment, and every new pairing is an initial sync.
- Detect: excluded records present in Salesforce.
- Prevent: test an excluded record in both directions; control sensitive data elsewhere.

Owner ping-pong

- Why: HubSpot owner rotation and Salesforce owner sync both assign owners; owner mapping is always two-way.
- Detect: owner property alternating between two users.
- Prevent: one system assigns owners.

Sync filter assumed to exclude forever

- Why: data sync filters only limit the initial sync; synced records keep syncing.
- Detect: records that no longer match the filter still updating.

Stale product data read as inactivity

- Why: a failed sync leaves old values; workflows treat them as current.
- Detect: `product_refreshed_at` older than the agreed window on active accounts.
- Prevent: freshness fields and workflow guards.

Integration overwrite discovered after the restore window

- Why: per-record property history restore appears only for CRM UI edits, imports and workflows. The account-level Restore CRM changes tool can roll back a named integration, import or workflow, but only to a point within the last 14 days, and only a Super Admin can run it.
- Detect: a wrong value whose history source is an integration; the first sync or backfill date is more than 14 days back.
- Prevent: before-exports for every backfill; permitted-field lists in custom integrations; a daily check during the first 14 days after each new writer goes live, with a named Super Admin who can run a restore.
- Repair: inside 14 days, preview a restore filtered to that integration; after that, rebuild from the before-export and the source system.

## Automation and reporting

Rotation counts reset

- Why: adding or removing owners in the rotation resets assignment counts.
- Detect: uneven distribution after a team change.

Everyone Away

- Why: "Assign to available users only" leaves records unowned when all users are Away.
- Detect: unowned records in the routing population.
- Prevent: a monitored fallback.

Credit exhaustion pauses a step

- Why: usage-based features pause by default when included credits run out and no pack was bought.
- Detect: workflow actions skipped or paused near month end; usage at 75, 85 or 90 percent notifications.
- Prevent: non-credit fallbacks for essential handoffs.

Inflated pipeline value

- Why: deal amounts summed after joining deals to contacts or workspaces.
- Detect: report total above the sum of distinct deal amounts.
- Prevent: deal-grain reporting and reconciliation to record IDs.

Currency change after deals exist

- Why: changing company currency does not convert existing amounts automatically.
- Detect: deal amounts unchanged after a currency switch.
- Prevent: set currency in layer 1, before any deal import.

Credential dead end

- Why: legacy private app creation is disabled for existing accounts from 26 October 2026; a plan that assumes a new private app stalls.
- Prevent: plan service keys or an app in the credential inventory.
