The first time a qpAdm model comes back with p = 0.003, most people assume something went wrong. Nothing did. A rejection is the method working: the mixture you proposed is incompatible with the data, and qpAdm is the only common ancestry tool that can tell you so. The useful question is not "how do I make it pass" but "what is it telling me". This post is the diagnostic list an analyst runs through for every rejection in Ancient Ancestry, our qpAdm analysis, and it is the same list a customer should follow in the Ancestry Workbench.
Not every strange number is an ordinary rejection, though. A negative weight, an SE of 9.994, a p-value of exactly 0 or NA, a run in which every model passes: each has causes of its own, and each is decoded below, from negative weights to the errors and odd outputs, with its meaning and its fix.
What p < 0.05 means, and does not#
The p-value tests one thing: whether the target's f4-statistics against the right populations can be written as a weighted combination of the sources' f4-statistics. Below 0.05, they cannot, at conventional confidence. The model is rejected.
What it does not mean:
- It does not mean the sources are unrelated to the target. A rejected three-source model may be missing a fourth source that accounts for 5% of the genome; the other 95% may be exactly as proposed.
- It does not mean the weights are wrong in any particular direction. They are simply not worth reading, because the model they belong to does not hold.
- It does not mean a higher-coverage file would pass. Coverage mostly sets the standard errors, not the p-value. A well-covered file rejects a wrong model more confidently, not less.
- It is not a probability that the model is false. It is a compatibility statement given this right set. Change the right set and the same left list can pass or fail.
The threshold itself is a convention. A model at p = 0.04 and one at p = 0.06 are almost the same evidence; the bar exists so that a publishing rule can be stated once and applied identically. The reading guide covers the other misreadings.
The five usual causes#
1. A missing source#
The most common cause by far. The right set contains a population that shares drift with the target in a way none of the sources explain, and the f4 pattern is inconsistent. In a European model this is typically the steppe source: Anatolia_N + WHG alone rejects for almost any living European because MA1, EHG and Karitiana.DG on the right detect Ancient North Eurasian ancestry the two sources lack. The rejection is the right set doing exactly what it is for.
Tell: the rejected model has a large chi-square against a modest number of degrees of freedom, and adding one well-chosen source drops it dramatically.
2. The wrong proxy#
The source is the right kind of population but the wrong sample of it. Anatolia_BA standing in for Anatolia_N carries an Iranian-related layer that Neolithic farmers lacked; Steppe_MLBA in place of Yamnaya_Samara carries a farmer-related layer the earlier steppe did not. The model may pass with distorted weights, or reject outright when the right set can see the extra layer.
Tell: the p-value moves a great deal when one label is swapped for a close relative, while the number of sources stays the same. How to choose sources and right populations goes through the label pairs that matter most.
3. A right population too close to a source#
If a right population shares recent drift with one source and not the others (EHG on the right with Yamnaya_Samara on the left; Natufian on the right with Levant_N on the left), the f4-statistics involving that pair are structured by the relationship, not by the target's ancestry, and the model fails for a reason that has nothing to do with the question asked.
Tell: the model passes when that one right population is removed, and the weights barely move. That is a sign the right population was contaminating the test rather than detecting anything.
On landscape-like histories there may be no single culprit to remove. In simulations of stepping-stone landscapes by Flegontova and colleagues (2025), the closer the right set sat to the target and its sources on average, the lower the p-values and the more often models were rejected.
4. Low coverage, which inflates SE while p can still be fine#
This one is included because people blame it for rejections, and it usually is not the cause. A sparse file produces large standard errors and small Z-scores; it does not, by itself, drive the p-value down. A model on a 90,000-marker file can sit at p = 0.4 with every source at |Z| < 2. That is a different failure: not a rejection, but a model too imprecise to publish. Ancestrify's bar requires every SE < 0.10 and every |Z| > 3 alongside p > 0.05, so a low-coverage file can fail the bar on the error terms while the p-value looks comfortable.
Tell: p above 0.05, standard errors above 0.10, and low SNP counts behind the f4-statistics (the minimum per f4 and the merged total, both in the model record). The free Raw DNA File Check rules out a truncated or edited export before anything runs, but how well a file overlaps the ancient panel is only measured during the analysis.
5. A target that is itself a mixture of mixtures#
Some genomes are not well described by two to four ancient sources against any right set, because their history involves several admixture events between already-mixed populations. Every proposed model is a little wrong, and a sufficiently strong right set rejects all of them. This is a real finding about the target, not a failure of technique.
Tell: many different plausible models all sit at p between 0.001 and 0.03, none dramatically better than the others, and the four-source models have rank tests that pass one rank too early.
The nested-model table#
Before treating a rejection as informative, check that the passing models around it are honest.
For every model, qpAdm can refit each simpler model obtained by removing one or more sources
(ADMIXTOOLS 2 prints this as its popdrop table). An illustrative table:
| Sources removed | Anatolia_N | Yamnaya_Samara | WHG | p-value | Feasible |
|---|---|---|---|---|---|
| none (full model) | 0.487 | 0.334 | 0.179 | 0.163 | yes |
| WHG | 0.612 | 0.388 | dropped | 0.0004 | yes |
| Yamnaya_Samara | 0.803 | dropped | 0.197 | 1.1e-19 | yes |
| Anatolia_N | dropped | 0.417 | 0.583 | 6.3e-22 | yes |
Every simpler model rejects, so every source earns its place. When a row in this table passes, the simpler model is the one to prefer: relative to this right set, the extra source is not needed. That is parsimony relative to the right set, not a count of the migrations in the target's history, and it is the check that stops "add sources until it passes" from working.
Negative weights#
qpAdm does not constrain weights to lie between zero and one. A negative weight means the best linear fit pushes one source below zero and inflates the others to compensate, and it is nearly always a sign that the sources are badly chosen. Illustrative:
p-value: 0.09
Anatolia_N 0.531 SE 0.041 Z 12.9
Yamnaya_Samara 0.372 SE 0.044 Z 8.5
WHG 0.138 SE 0.036 Z 3.8
CHG -0.041 SE 0.038 Z -1.1
The p-value passes, and a careless reader might report "0% CHG". The honest reading is that CHG is not a source here, the model is really a three-source model, and the fourth term is absorbing noise. Run the three-source nested model; if it passes, publish that.
A small negative weight inside its error, like this one, is noise. A large one, several standard errors below zero, says something stronger: the best fit lies outside anything a real mixture can produce, because no combination of these sources with non-negative weights reproduces the target's f4 pattern. Usually the pool brackets the target wrongly (the sources sit on the same side of it along some axis the right set can see), or a needed ancestry component is missing entirely. Treat the sign as a diagnosis, not a rounding error, and rethink the pool: the negative source is often related to the right answer without being it.
qpAdm flags a model infeasible when any of its weights falls outside zero to one, and no
Ancestrify model with a negative weight is published. Forcing the sign away with
the constrained option fixes nothing.
|Z| below 3 with p fine#
The quieter cousin of a rejection. The model passes, but one source's weight is within a few standard errors of zero:
p-value: 0.27
Anatolia_N 0.612 SE 0.033 Z 18.5
Yamnaya_Samara 0.335 SE 0.035 Z 9.6
Levant_N 0.053 SE 0.031 Z 1.7
At |Z| = 1.7, the Levant_N weight is not distinguishable from zero at the confidence the method works at. Ancestrify's bar requires every source above |Z| = 3, which is why this model would not be published as it stands. The correct step is the same as for a negative weight: test the nested two-source model. If it passes, publish it; if it rejects, the Levant_N source is needed but the file cannot pin its weight, and that is the honest conclusion.
Errors and odd outputs#
Negative weights and low Z-scores, above, are the odd outputs everyone meets first, and a run in which every model rejects is covered under when to stop. These are the rest.
SE = 9.994, or errors wider than the weight#
A weight of 0.4 with an SE of 10 is not an estimate: the model has run out of information. Three things do that.
- Too few SNPs. What counts is the number behind each f4-statistic, not the file's marker count; the arithmetic is in how many SNPs qpAdm needs.
- Sparse data with
allsnpsoff. The 9.994 is a published figure: in simulations by Harney and colleagues (2021) with 90% missing data, the average standard error was 9.994 without the allsnps option and 0.035 with it. In ADMIXTOOLS 2 the option works only whenqpadm()reads the genotype files directly, not precomputed f2 blocks (the settings that change results). - Two sources the right set cannot tell apart. When two sources are nearly a clade relative to every right population, the model cannot apportion what they share, and their weights swing to opposite extremes. The example in the ADMIXTOOLS 2 documentation does exactly this: a Denisovan modelled from two Neanderthal genomes gets weights of 49.6 and -48.6, each with an SE of 23.3.
The fix, in that order: read the SNP counts in the output; switch on allsnps if the data are sparse; and test the suspect pair with qpWave, dropping one if they form a clade relative to the right set. Cause 4 above is the mild form of the same problem.
Every model passes#
Four different stories all passing at p > 0.3 is not generosity; it is a test with no power to choose. Either the right set is too small (the degrees of freedom are the number of right populations minus the number of sources, so a set at the floor leaves almost nothing to test), or it relates to every candidate source in much the same way, so nothing it measures separates them (what f4-statistics can see). Distance matters too: on the simulated landscapes of Flegontova and colleagues (2025), right sets far from the target and its sources produced higher p-values on average and let searches stop at simpler models.
The fix is to add right populations that relate differently to the competing sources. In their study of the Bronze Age Southern Levant, Agranat-Tamir and colleagues (2020) added Neolithic Anatolia to the right set and cut the standard errors of the mixture weights threefold in one model and 2.1-fold in another; the set they built, o9a, is one of the standard right sets. Once several models pass, choose between them on margins, feasibility and stability across right sets, never by ranking p-values: in the simulations of Harney and colleagues (2021), the model with the best-placed sources had the highest p-value in only 48% of cases (how to read the three numbers).
A nested-model table where nothing is feasible#
The nested-model table marks each simpler model feasible or not. "Infeasible" does not mean the row could not be computed: every row was fitted, and the flag means that sub-model's weights fall outside zero to one, which no real mixture can produce. So a table in which every simpler model is infeasible or rejected, under a full model that passes with every weight clearly away from zero, is the good outcome: each source is earning its place. The row that should worry you is a simpler model that is feasible and passes, because that is the model to prefer (the nested-model table, above). A model that could not be tested at all shows no p-value, which is the next case.
p = 0 exactly, or p = NA#
A p-value printed as exactly 0 is a chi-square so large that the probability is smaller than the software can represent. A wildly wrong model can do that: in the same ADMIXTOOLS 2 example, a Denisovan modelled from either Neanderthal alone scores a chi-square above 11,000 and p = 0. When a historically plausible model does it, suspect the inputs before the model: a right population that is a close relative of a source or of the target, or a processing fault (a genome-build mismatch, strand flips, a merge gone wrong). Check the merge itself (population labels, reference build, SNP counts per population) before changing a single source; for a consumer file, the free file check confirms that the export is complete and readable.
NA is a different message. In ADMIXTOOLS 2, qpadm() returns NA when the model has zero degrees
of freedom, which happens when there are exactly as many right populations as sources: the weights
can still be fitted, but nothing is left to test them against. Add right populations, at least one
more than there are sources and in practice well above that floor
(every model passes, above).
Forcing positive weights with constrained#
ADMIXTOOLS 2's qpadm() has an option, constrained = TRUE, that constrains the weights to be
non-negative. It makes the minus sign disappear, and that is the problem: the sign was the
diagnosis (negative weights, above). A constrained fit of a badly chosen pool
returns tidy-looking weights and hides the fact that no real mixture of those sources reproduced
the target. Diagnose unconstrained, and trust only a model that is feasible without being forced.
The meta-fix#
Most of this section is one lesson in different costumes: a qpAdm model has two inputs, and most breakage is input breakage. The sources decide what can be estimated, the right set decides what can be tested, and coverage decides how sharply. Before changing a model because of an odd number, find out which of the three produced it.
What to try next, in order#
- Read the right set first. Is any right population a parent, descendant or close relative of a source? Move it or drop it, rerun, and see whether the weights move. If they do not and the model now passes, the right population was the problem.
- Check chronology. No source should postdate the target's era, and nothing on the right should be a mixture of things on the left.
- Try one more source, chosen by asking which right population the target shares unexplained drift with. If EHG and MA1 are the loud ones, the missing source is steppe-related. If Han.DG is, it is East Asian-related. One source, not three.
- Swap proxies before adding sources. Anatolia_N for Iberia_N, Yamnaya_Samara for Steppe_MLBA, Iran_N for CHG. Rerun with the same right set each time so that p-values are comparable.
- Run the nested models on anything that passes. Publish the simplest model that survives.
- Rotate as a diagnostic, not a search. Move each candidate source to the right in turn and confirm the model still needs it.
- Check the file. If every model's SEs sit above 0.10 whatever the sources and right set, no search will fix it; the file sets that floor.
What is not on the list: rerunning combinations until one passes. Run enough models and some will clear any threshold by chance, and the best-scoring model is frequently not the right one; Harney and colleagues (2021) documented this failure mode. An automated search can propose candidate models, but it cannot publish one: a person reviews the candidates and approves every published model. The audit literature's lesson is that a search's error rate depends mostly on how plausible its candidates were before testing (its pre-study odds), not on whether a script or a person ran it.
When to stop#
A rejected model is information. When every model rejects, the historically obvious candidates included, suspect the right set before the target. Two things do it: a right population too close to a source or to the target (cause 3 above), and a right set that has simply grown too large. In simulations by Harney and colleagues (2021), qpAdm began rejecting models built from the correct sources once as few as 30 extra populations had been added to the right set, and where that starts depends on the history and the amount of data. Remove the suspect, or rebuild on one of the standard right sets, and rerun. If the rejection survives a clean right set, the pool is missing a component this right set can see, and the rank test says how many more components the data need relative to it.
If, after that and the steps above, every plausible two- to four-source model still rejects against a strong right set, the finding is that the target's history is not well-described by the sources available in the panel, and the honest result says so rather than presenting the least-bad model as a fit. Some genomes, at some coverage, with the ancient samples currently excavated, cannot be modelled to the bar. That is an honest result.
Ancestrify's bar is a house convention, stated once and applied identically to every order: p > 0.05, every source at |Z| > 3 and every SE < 0.10, in every era. A model below it is never published by default, and a report is never delivered with an era missing. When the search is exhausted and an era's strongest model still falls short, delivering it is a person's explicit decision, and the report marks that era "Below the bar" instead of presenting it as a pass.
How Ancestrify handles it#
Candidate sources are fixed before any model runs: a pool curated for the customer's declared origins and era. Our analyst tests models drawn from that pool, automated searches included, and re-tests the survivors on alternative right sets and against their simpler nested models; a person reviews the candidates, chooses the model to publish and approves it. The pool is our main lever on pre-study odds. The search inside it is large, which is why a published model is best read as one adequate description of a genome relative to the sampled groups, not as proof that those groups mixed.
Every published model comes with its model record: per era, seven fit figures (the p-value, chi-square, degrees of freedom, f4 rank, minimum SNPs per f4-statistic, merged SNPs and jackknife blocks) under a verdict against our bar; a sources table giving each source's sample count, share, weight, SE, Z and 95% CI; and the right populations with their sample counts. The nested-model table, the rank test and the tool's warnings are what the analyst checked before a model was proposed; they are not printed in the report. The record is described in The model record explained, and a sample is on the demo.
The Ancestry Workbench lets you run the diagnostic list above yourself, on your own merged sample, and see the rejections and odd outputs for what they are (how it works); the owner of an order can open its published model there from the report's Your model view. If you want the whole process done and defended for you first, Ancient Ancestry starts at 29.99 EUR. Every tier gets the same report, maps and videos, the same model record and the same publish bar (what it costs).
References#
- Agranat-Tamir, L. et al. (2020). The genomic history of the Bronze Age Southern Levant. Cell, 181(5), 1146 to 1157.
- Flegontova, O. et al. (2025). Performance of qpAdm-based screens for genetic admixture on graph-shaped histories and stepping stone landscapes. Genetics, 230(1), iyaf047.
- Harney, É., Patterson, N., Reich, D. & Wakeley, J. (2021). Assessing the performance of qpAdm: a statistical tool for studying population admixture. Genetics, 217(4), iyaa045.
- Maier, R. et al. (2023). On the limits of fitting complex models of population history to f-statistics. eLife, 12, e85492.
- Patterson, N. et al. (2012). Ancient admixture in human history. Genetics, 192(3), 1065 to 1093.
- ADMIXTOOLS 2 documentation: the
qpadm()reference (thepopdroptable, theallsnpsandconstrainedoptions, and the Denisovan example quoted above).



