法國税務審計:FEC 的 18 個欄位及 10 種常見錯誤
The 18 FEC columns and the 10 errors that fail a French tax audit
這份指南列出法國商業利潤或公司税納税人提交的 FEC 固定 18 個欄位,並説明 10 種可能令檔案不符規定的錯誤及修正方法。FEC 遲交或格式不合規,可按法國《税法典》第 1729 D 條被罰款 €5,000。遠程審計中,公司須在收到通知後 15 天內提交檔案。
Every French company that keeps its books on a computer must be able to hand the tax administration one file: the FEC, Fichier des Écritures Comptables. Accounting software exports it in one click, so everyone assumes it is correct.
It often isn't. A FEC that is late or does not follow the required format costs a €5,000 fine under article 1729 D of the French tax code (CGI). For a remote audit (examen de comptabilité), the administration's own guidance, updated in January 2026, applies it once per audit (BOI-CF-DG-40-20 § 390). Worse than the fine, a file the auditor cannot read is a bad start to an audit.
This guide lists the 18 columns, then ten errors I see in real exports, each with a bad line, why it fails and the fix. Every example below comes from synthetic files and from the output of two checkers I wrote; the rules are checked against the official text.
What a FEC is
Since 2014, a company under audit must hand over its accounting entries as a file at the start of the audit (article L47 A of the Livre des procédures fiscales, LPF). For a remote audit, it has 15 days from the notice. The format is fixed by article A47 A-1 LPF and explained in the administration's guidance BOI-CF-IOR-60-40-20.
The file holds every entry recorded during the fiscal year, opening balances included, one line per entry line. Most companies send a flat text file; an XML format also exists, but this guide covers the flat file.
The 18 columns
For a company taxed on commercial profits (BIC or corporate tax), the file has exactly these 18 columns, in this order. Cash-basis non-commercial and agricultural filers add columns (22 and 21); they are out of scope here.
| # | Column | Content | Example |
|---|---|---|---|
| 1 | JournalCode | Journal code | VE |
| 2 | JournalLib | Journal name | Ventes |
| 3 | EcritureNum | Entry number, on a continuous sequence | 000039 |
| 4 | EcritureDate | Accounting date, AAAAMMJJ
|
20250610 |
| 5 | CompteNum | Account number | 411000 |
| 6 | CompteLib | Account name | Clients |
| 7 | CompAuxNum | Sub-ledger account (customer, supplier); may be empty | CLI001 |
| 8 | CompAuxLib | Sub-ledger account name; filled when 7 is | Atelier Durand |
| 9 | PieceRef | Supporting document reference | F2025-06 |
| 10 | PieceDate | Document date, AAAAMMJJ
|
20250610 |
| 11 | EcritureLib | Entry label | Facture F2025-06 Atelier Durand |
| 12 | Debit | Debit amount, decimal comma | 3960,00 |
| 13 | Credit | Credit amount, decimal comma | 0,00 |
| 14 | EcritureLet | Matching (lettrage) code; may be empty | AA |
| 15 | DateLet | Matching date; filled when 14 is | 20250712 |
| 16 | ValidDate | Date the entry was validated | 20250610 |
| 17 | Montantdevise | Amount in foreign currency; may be empty | 1200,00 |
| 18 | Idevise | Currency code; filled when 17 is | USD |
A full line looks like this (pipe-separated):
VE|Ventes|000039|20250610|411000|Clients|CLI001|Atelier Durand|F2025-06|20250610|Facture F2025-06 Atelier Durand|3960,00|0,00|||20250610||
If your software has no separate debit and credit, the text allows Montant and Sens (D/C or +1/-1) instead of columns 12 and 13. Most exports use Debit/Credit.
The 10 errors
1. Wrong file name
FEC_2025.txt
Why it fails: the name is part of the format: the company's SIREN, the letters FEC, then the fiscal year's closing date as AAAAMMJJ (A47 A-1, IX).
Fix: 123456782FEC20251231.txt for SIREN 123456782 and a year closing on 31 December 2025. The text fixes the name, not the extension; .txt is the usual choice for the flat file. Also check that the SIREN is right: it has a Luhn check digit, so a typo is often detectable.
2. Mixed or wrong separator
VE|Ventes|000002|20250310|411000|Clients|||F000002|20250310|Facture F1|120,00|0,00|||20250310||
VE;Ventes;000002;20250310;706000;Prestations;;;F000002;20250310;Facture F1;0,00;120,00;;;20250310;;
Why it fails: fields are separated by a tab or a pipe (|), the same one for the whole file (A47 A-1, VI). Semicolons, the default of many spreadsheets in France, are not allowed. The second line above has 1 field instead of 18 for a pipe reader, so the checker reports field_count on line 5, and the entry then looks unbalanced because half of it cannot be read.
Fix: export the FEC from the accounting software, never through a spreadsheet. If you must edit it, save as "text (tab-separated)" and check that no label contains the separator.
3. Broken accents
VE|Ventes|000002|20250310|411000|Clients|||F000002|20250310|Facture réglée|120,00|0,00|||20250310||
Why it fails: the allowed encodings are ASCII, ISO 8859-15 and UTF-8 (A47 A-1, XII). réglée is "réglée" encoded twice: someone opened a UTF-8 file as Latin-1 and saved it as UTF-8 again. The labels are now wrong in the copy the auditor reads.
Fix: pick one encoding and never re-save the file in a text editor or spreadsheet. A file in UTF-16 ("Unicode text" in Excel) is outside the list too: re-export it as UTF-8.
Be aware: no automatic check can be sure here. A double-encoded label is still valid UTF-8, so both tools below accept it. Search the file for à before sending it.
4. Misspelled or reordered headers
JournalCode|JournalLib|EcritureNum|DateEcriture|CompteNum|CompteLib|CompAuxNum|CompAuxLib|PieceRef|PieceDate|EcritureLib|Credit|Debit|EcritureLet|DateLet|ValidDate|Montantdevise
Why it fails: three problems in one line. DateEcriture instead of EcritureDate, Credit before Debit, and Idevise missing. The checker reports:
error header_count x1: The header must contain exactly 18 columns.
error header_missing x2: Mandatory column missing from the header: EcritureDate.
error header_unknown x1: Header column not defined by article A47 A-1.
error header_order x1: The header columns are not in the required order.
Fix: copy the header from the table above, exactly, case included. Empty optional columns stay in the header.
5. Dates not in AAAAMMJJ
AC|Achats|000009|20250230|613200|Locations immobilieres|||FL02|20250205|Facture FL02 SCI Les Tilleuls|1200,00|0,00|||20250205||
AC|Achats|000026|12/04/2025|626000|Frais postaux et telecom|||FT04|20250411|Facture FT04 Telecom Ouest|89,90|0,00|||20250411||
Why it fails: dates are AAAAMMJJ with no separator (A47 A-1, XII). 12/04/2025 has the wrong format. 20250230 has the right format but does not exist (there is no 30 February), which a format check alone misses:
error date_invalid x3: Non-existent date in EcritureDate. - line(s) 21, 22, 23
error date_format x3: Wrong date format in EcritureDate (expected AAAAMMJJ). - line(s) 64, 65, 66
Fix: set the export's date format in the software. A non-existent date usually comes from a manual entry: correct the entry, then export again.
6. Decimal point or thousands separators in amounts
VE|Ventes|000002|20250310|411000|Clients|||F000002|20250310|Facture F1|120.00|0,00|||20250310||
VE|Ventes|000002|20250310|411000|Clients|||F000002|20250310|Facture F1|1 200,00|0,00|||20250310||
Why it fails: the comma separates units from decimals, and no thousands separator is accepted (A47 A-1, XII). 120.00 and 1 200,00 both fail.
Fix: 120,00 and 1200,00. One detail people get wrong in the other direction: a negative amount may carry its sign as the first character on the left or the last on the right (-150,00 or 150,00-), both are legal.
7. Unbalanced entries
VE|Ventes|000039|20250610|411000|Clients|CLI001|Atelier Durand|F2025-06|20250610|Facture F2025-06 Atelier Durand|3960,00|0,00|||20250610||
VE|Ventes|000039|20250610|706000|Prestations de services|||F2025-06|20250610|Facture F2025-06 Atelier Durand|0,00|3200,00|||20250610||
VE|Ventes|000039|20250610|445710|TVA collectee|||F2025-06|20250610|Facture F2025-06 Atelier Durand|0,00|660,00|||20250610||
Why it fails: double-entry bookkeeping. The lines of one entry (same EcritureNum) must have total debit = total credit, and so must the whole file. Here 3960,00 debit against 3860,00 credit:
error entry_unbalanced x1: Unbalanced entry: debit - credit difference of 100,00.
error file_unbalanced x1: The file is unbalanced: total debit 193104,48, total credit 193004,48, difference 100,00.
Fix: software does not book unbalanced entries, so this almost always means the export lost or changed lines: a filter on accounts, a truncated label that shifted a column, or a manual edit. Find the entry by its number and compare with the ledger.
8. Gaps or duplicates in EcritureNum
AC|Achats|000046|20250704|401000|Fournisseurs|FOU002|SCI Les Tilleuls|FL07|20250704|Facture FL07 SCI Les Tilleuls|0,00|1440,00|||20250704||
VE|Ventes|000050|20250710|411000|Clients|CLI002|Boulangerie Martin|F2025-07|20250710|Facture F2025-07 Boulangerie Martin|4140,00|0,00|||20250710||
Why it fails: EcritureNum is "the number on a continuous sequence" (A47 A-1, VII). Entries 47 to 49 are missing, which is exactly what an auditor looks for: deleted entries.
error num_gap x1: Numbering gap: 3 number(s) missing, from 47 to 49.
The sequence can be global or per journal (VE0001, AC0001…); a checker has to work out which one the file uses before counting gaps. The same number used twice for two different entries is the opposite error.
Fix: if entries were really deleted, the file shows it and you need an explanation. More often, the export left out a journal or a period: export the whole fiscal year, all journals.
9. Missing ValidDate or validation out of order
VE|Ventes|000002|20250310|411000|Clients|||F000002|20250310|Facture F1|120,00|0,00|||||
Why it fails: ValidDate is the date the entry became final and can no longer be changed. The file is sorted in chronological order of validation (A47 A-1, VII), so an empty ValidDate means a draft entry was exported. Dates going backwards against the numbering are a red flag too:
error validdate_not_chronological x1: Validation date earlier than that of entry no. 71 (20251020): validation must follow numbering order.
Fix: validate (close) the draft entries for the year in the software, then export again.
10. Opening entries missing or misplaced
VE|Ventes|000001|20250310|411000|Clients|||F000001|20250310|Facture F1|120,00|0,00|||20250310||
VE|Ventes|000001|20250310|706000|Prestations|||F000001|20250310|Facture F1|0,00|120,00|||20250310||
AN|A-nouveaux|000002|20250101|512000|Banque|||AN2025|20250101|Reprise des soldes|15000,00|0,00|||20250315||
AN|A-nouveaux|000002|20250101|101000|Capital|||AN2025|20250101|Reprise des soldes|0,00|15000,00|||20250315||
Why it fails: the file must include the entries that record the opening balance sheet (à-nouveaux), and they normally take the first entry numbers of the year (A47 A-1, VII). The administration accepts them later in the file only if they cannot come first and the auditor can still identify them (BOI-CF-IOR-60-40-20). A file with no opening entries at all does not let the auditor check the balances.
Fix: include the opening journal (usually AN) in the export and number it first. Be aware: I know of no automatic checker, including mine, that verifies this today; check it by eye in the first lines of the file.
A 20-line header check in Python
The header causes a large share of rejections and is the easiest thing to check. This is the header logic of fec-lint, reduced to plain Python with no dependency:
EXPECTED = ['JournalCode', 'JournalLib', 'EcritureNum', 'EcritureDate', 'CompteNum', 'CompteLib',
'CompAuxNum', 'CompAuxLib', 'PieceRef', 'PieceDate', 'EcritureLib', 'Debit', 'Credit',
'EcritureLet', 'DateLet', 'ValidDate', 'Montantdevise', 'Idevise']
def check_header(path, encoding='utf-8'):
with open(path, encoding=encoding) as f:
header = f.readline().lstrip('').rstrip('\r\n')
sep = '\t' if '\t' in header else '|' if '|' in header else None
if sep is None:
return ['no tab or pipe separator in the header']
names = [n.strip() for n in header.split(sep)]
errors = []
if len(names) != 18:
errors.append(f'{len(names)} columns instead of 18')
errors += [f'missing column: {n}' for n in EXPECTED if n not in names]
errors += [f'unknown column: {n}' for n in names if n not in EXPECTED]
found = [n for n in names if n in EXPECTED]
if found != [n for n in EXPECTED if n in found]:
errors.append('columns are not in the required order')
return errors
On the header from error 4 it returns:
17 columns instead of 18
missing column: EcritureDate
missing column: Idevise
unknown column: DateEcriture
columns are not in the required order
Two details matter. The order check compares only the columns that were found, so a missing column does not hide a swap. And lstrip('') removes the byte-order mark some Windows tools add, which would otherwise make the first column JournalCode.
How to check your own file
- Test Compta Demat, the administration's free tool, checks the file the way the DGFiP reads it. Start there; it is the reference.
-
fec-lint, free and open source (MIT): errors 1, 2, 4, 5 and 6, a UTF-16 file for error 3 and an empty
ValidDatefor error 9, as a command line tool and an MCP server for AI assistants. It runs on your machine and the file never leaves it.
pipx install fec-lint
fec-lint 123456782FEC20251231.txt
- FEC Checker, the full pre-audit: everything above plus balance, numbering, validation order, risk signals (weekend postings, round amounts, Benford's law, cash and suspense accounts) and an optional AI-written fix list, in French or English: FEC Checker on Apify.
None of these replaces reading the first and last lines of the file yourself, especially for errors 3 and 10.
Technical guide, not tax advice. It describes the published file format; it does not tell you how the administration will judge your accounts. For that, ask your accountant (expert-comptable).
來源:DEV Community · dev.to