Validate incoming files before you spend money enriching them or write to your CRM. A useful validation gate checks the file structure, the identity of each row and the rules for each destination field. It produces accepted rows and an exception file with explicit reasons. A file that parses successfully can still contain the wrong people, duplicate accounts or conflicting identifiers.
This guide covers B2B lead and account imports. For broader ownership and correction policies, use CRM data quality automation. For the enrichment stage after validation, follow the CSV email enrichment walkthrough.
Start with an input contract
Write down which fields identify a record and which fields are merely supporting evidence. Preserve the original row ID throughout the workflow. Never use the spreadsheet row number as the only identity across different exports.
| Field | Acceptance rule | On failure |
|---|---|---|
| source_record_id | Present and unique within the source system | Hold the row; ask the source owner to repair it |
| crm_record_id | If supplied, resolves to the intended object | Hold missing or conflicting records |
| company_domain | Valid hostname when company matching requires it | Preserve raw input and record the normalization error |
| Parsed address when the selected workflow requires email | Hold malformed values; verify deliverability separately | |
| observed_at | Parseable timestamp for fields with a freshness policy | Mark stale or unknown rather than inventing a date |
An account-domain workflow does not need the same required fields as a person-to-email workflow. Inspect the selected action or Play before making fields mandatory. A missing phone number is not a file error when finding that phone number is the job.
Parse CSV as CSV
Use a CSV parser that handles quoted commas, embedded line breaks and escaped quotes. Splitting a line on commas can turn one person's company name into several columns. RFC 4180 documents common CSV conventions, including quoted fields and a consistent number of fields per record.
Reject duplicate headers: two columns both called email create an ambiguous mapping. Decide how to handle a byte-order mark, blank lines and encoding before a recurring import runs. Keep the original file intact and produce a separate normalized file.
This illustrative input includes a quoted company name and a duplicate source identity:
source_record_id,first_name,last_name,company_name,company_domain
lead-101,Alex,Example,"Example, Inc.",example.com
lead-101,Alex,Example,Example,example.org
The second row should not silently overwrite the first. Hold both for identity review because the same source ID points at conflicting company evidence.
Separate file failures from row failures
A missing required header should fail the whole import. One invalid address can go to an exception file while independent valid rows proceed, if partial processing is part of the contract. Give every row exactly one terminal disposition.
| Disposition | Meaning | Next action |
|---|---|---|
| accepted | Structure and required identity checks passed | Eligible for the next enrichment stage |
| rejected | Deterministic contract violation | Repair the source field and submit a new revision |
| review | Conflicting identities or competing evidence | Assign a named reviewer |
| retryable_error | Dependency failed before validation finished | Retry with a bound and preserve the error |
Reconcile the counts: input rows must equal accepted, rejected, review and retryable-error rows combined. Report counts for each reason code, such as duplicate_source_id or unresolved_crm_id. A blank output cell should never be the only indication that processing failed.
Worked import: five rows, one accepted
Assume this example import requires a unique source_record_id and a company domain. Phone is optional. The domains and records below are fictional; the rules are specific to this example.
source_record_id,company_domain,phone
lead-101,example.com,
lead-102,example.org,
lead-102,example.net,
lead-103,not a hostname,
lead-104,,
Scan the whole file for duplicate IDs before exporting accepted rows. A streaming implementation that releases the first lead-102 before seeing the second would miss the conflict.
The accepted file contains only lead-101. Its empty phone field is allowed. The exception file is:
input_record,source_record_id,disposition,reason,repair_owner
2,lead-102,review,conflicting_duplicate_id,source owner
3,lead-102,review,conflicting_duplicate_id,source owner
4,lead-103,rejected,invalid_company_domain,source owner
5,lead-104,rejected,missing_company_domain,source owner
input_record is a locator within this file revision, counting data records after the header; it is not a persistent identity or a physical line number. Quoted multiline fields can span several lines. Keep both this locator and the source ID so the owner can repair either duplicate.
The reconciliation is 5 input = 1 accepted + 2 review + 2 rejected + 0 retryable errors. Resolving the duplicate means correcting the source identity or explicitly merging the records; deleting an arbitrary duplicate is not a repair.
Implement and check the same boundary
Use a parser to load records, check the header once, group by source identity, evaluate field rules, and write the two outputs. Do not call enrichment providers inside that validation pass. Store the input file revision with the counts so a repaired file cannot be mistaken for the earlier result.
Use the five-row example as an acceptance fixture. Then add a quoted comma, an embedded newline, duplicate headers, and a missing required header. The first two should parse as field content; the last two should fail the file before any accepted export is produced. For the enrichment stage, follow the CSV walkthrough.
Decide when the file is ready
Accepted means ready for the next stage, not verified, qualified or authorized for outreach. Email deliverability, person matching and CRM field ownership need their own checks. Follow the pre-send verification guide if the final destination is an outbound campaign.
Keep the input version, contract version and validation receipt together. If someone changes the source file, validate that revision again. When exporting values for spreadsheet use, account for formula interpretation of untrusted cells; a technically valid CSV is not automatically safe to open in every spreadsheet application.
Questions operators ask
Should we reject the entire file for one bad row?
Reject the file when its structure or mapping is ambiguous. For isolated row problems, use a documented partial-processing policy and preserve every rejected row for repair.
Does an email format check verify a mailbox?
No. Parsing checks structure. A verification service supplies separate deliverability evidence, and that evidence still does not establish permission to contact the person.
What should we measure?
Track exception rate by source and reason, time to repair, repeated failures and rows that reached the next stage. Fix recurring upstream errors instead of repeatedly cleaning the same export.
Sources and next steps
The CSV conventions above use RFC 4180, checked September 14, 2026. The validation contract and examples are proposed operating patterns, not measured customer results. Continue with waterfall enrichment once the accepted file is ready.