# XBRL duplicate fact values conflict, validation failed

## TL;DR
Duplicate XBRL facts with conflicting values are usually not duplicates at all: same tag, different contexts, like quarterly versus annual or different segments. Validation fails when code compares values without comparing contexts. Resolve by keying every fact on tag plus context, and only treat same-tag same-context facts as true duplicates, which usually trace to amended filings mixing old and new instances.

## The error
```text
XBRL validation failed: duplicate fact values conflict
tag [us-gaap Revenues] has 3 different values for the same period
```

## When this helps
- XBRL validation fails on duplicate fact conflicts
- the same tag shows multiple values for one period
- deduplicating facts from instance documents
- validating a new XBRL pipeline

## When it doesn't
- values differ across contexts; that is normal, not duplication
- the instance failed to parse; fix parsing first
- you need segment detail; filter dimensions instead of flagging duplicates

## Works with
python 3.9+ with arelle. Context semantics follow XBRL 2.1.

## Steps
### 1. Group the conflicting facts by their contexts
```python
from arelle import Cntlr
cntlr = Cntlr.Cntlr()
model = cntlr.modelManager.modelXbrl
model.load("instance.xml")
seen = {}
for f in model.facts:
    if f.qname.localName == "Revenues":
        seen.setdefault(f.context.id, []).append(f.value)
for cid, vals in seen.items():
    print(cid, vals)
```
Expected: Values grouped by context id. Different contexts explain most conflicts immediately.

### 2. Check whether the contexts differ by period or segment
```python
from arelle import Cntlr
cntlr = Cntlr.Cntlr()
model = cntlr.modelManager.modelXbrl
model.load("instance.xml")
for cid, ctx in model.contexts.items():
    per = ctx.instantDatetime if ctx.isInstantPeriod else (ctx.startDatetime, ctx.endDatetime)
    print(cid, per)
```
Expected: The period behind each context. Quarterly versus annual durations are the most common false duplicate.

### 3. Treat only same-context conflicts as real duplicates
```python
from arelle import Cntlr
cntlr = Cntlr.Cntlr()
model = cntlr.modelManager.modelXbrl
model.load("instance.xml")
real = {}
for f in model.facts:
    k = (f.qname.localName, f.context.id)
    real.setdefault(k, set()).add(str(f.value))
dupes = {k: v for k, v in real.items() if len(v) != 1}
print("true duplicates:", len(dupes))
```
Expected: A count of genuine same-context conflicts. Zero means the validation error was a context-blind comparison.

### 4. Resolve true duplicates to the latest amendment
```bash
curl -s -A "IntelBriefingBot/1.0" "https://www.sec.gov/cgi-bin/browse-edgar?action=getcompany&CIK=[cik]&type=10-K&count=10" -o filings.html
grep -c "10-K/A" filings.html
```
Expected: The amendment count. True same-context duplicates usually mean instances from an original and an amendment got mixed; keep only the latest accession.

## Other ways people phrase this
### xbrl duplicate facts same tag different values
Check contexts first. Same tag with different contexts is correct data.

### xbrl validation duplicate fact error
Validators flag same-context duplicates. Context-blind code flags everything.

### conflicting revenue values xbrl 10-k
Quarterly and annual revenue contexts collide in naive comparisons. Key by context.

## Why it happens
XBRL facts are identified by tag plus context, not tag alone. One tag legitimately carries many values across periods, segments, and restatements. Validation that compares values by tag alone manufactures conflicts from correct data. Genuine duplicates, same tag and same context with different values, are rare and usually mean mixed filings.

## Edge cases
- Amended filings reissue facts with identical contexts; never load an original and amendment into one model.
- Segment dimensions create contexts that look identical on dates; include dimensions in the key.
- Nil-valued facts versus missing facts are different; handle nil explicitly.
- The companyfacts API dedupes to one value per tag per period, which hides this complexity entirely.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_W-bJxTPEGLLNyrsaJ5tOng
