FalkorDB
Solutions
Use cases
Why FalkorDB
Developers

Your Hugging Face Model May Inherit a Restricted License

Hugging Face model license check: a model family tree with a restricted ancestor and a flagged descendant glowing pink

Graph Hacks, FalkorDB's online hackathon (October 15 to 18, 2026, with $20K in prizes), drew 7,899 developers and 1,213 projects. One of them, FinePrint by Dhiraj Kavuri, put all 3,161,594 public Hugging Face models into one FalkorDB graph and checked whether each Hugging Face model license matches the terms of the models it was built on. For 48,975 models it doesn't. They declare apache-2.0, MIT or another permissive license while an ancestor carries restricted terms, and they had 5.88 million downloads in 30 days.

Key takeaways. FinePrint found 242,170 Hugging Face models that inherit restricted terms through their declared base models. 48,975 of them declare a permissive license anyway, and 11,442 say commercial use is fine while an ancestor's license is non-commercial. License terms travel the whole lineage path, so finding them is a graph traversal. On FalkorDB, a verdict for one model takes 3 to 70 ms and each Hub-wide count about a second.

Have data where the answer is a path, not a row? Start free on FalkorDB Cloud and run your first lineage query today.

What is Hugging Face model license inheritance?

Hugging Face model license inheritance is the idea that a model built from another model, by fine-tuning, adapters, merging or quantization, can carry the terms of every model above it, not only the license its uploader typed on the card.

The model page shows only the declared license and the direct base model. Take kenpath/svara-tts-v1, a text-to-speech model with 103,429 downloads in 30 days. Its card, its parent and its grandparent all say apache-2.0. Three hops up sits meta-llama/Llama-3.2-3B-Instruct under the Llama 3.2 license. FinePrint answers CONDITIONS for commercial use, with five obligations quoted from the license text. Switch it to "direct parents only", which is what the model page shows, and the same model looks clean.

What did the graph find across 3.16M models?

Each number below is one Cypher count over the whole FalkorDB graph, with its saved query time.

What the graph countedQuery timeModels
Public models in one FalkorDB graph0.99 s3,161,594
Inherit restricted terms through declared base models0.52 s242,170
Of those, declare a permissive license (5.88M downloads in 30 days)0.50 s48,975
Of the 48,975, have 10 or more downloads0.25 s25,627
Of the 48,975, ship any license or notice file0.25 s346
Declare permissive while an ancestor is non-commercial (2.85M downloads)0.42 s11,442

Restricted families include Llama, Gemma, Qwen, FLUX, Mistral and CC BY-NC. By algo.pageRank over lineage, the most depended-on model on the Hub is black-forest-labs/FLUX.1-dev, under a non-commercial license.

The graph also shows where mismatches start. 38,489 models declare a permissive license directly on top of a restricted parent. 26,406 of the 48,975 (54%) carry the default tags from Unsloth's model card template, which sets apache-2.0, and Dhiraj proposed a fix for the template.

Why does a license check need a graph database?

A license belongs to one model. What a model inherits is a path. Merges have two or more parents and quantized copies add more hops, so the number of paths grows fast. That is a traversal, and FalkorDB runs it in milliseconds.

The Hugging Face API lists a model's direct children, 1,000 per page. Finding all 21,639 descendants of Llama-3.1-8B that way takes 21,653 calls, about 3.7 hours. FalkorDB returns the same set in 70 ms. FinePrint also scored itself on 120 sealed models, with gold labels built from the live Hub API.

QuestionModel page or Hub APIFinePrint on FalkorDB
Which terms does this model inherit?Declared tag and direct base modelEvery ancestor at any depth, each clause quoted
All 21,639 descendants of Llama-3.1-8B21,653 API calls, about 3.7 hours70 ms
Restricted terms 2+ hops up (19 test models)LLM agent with Hub API tools found 14Found all 19
Restricted models called clean (69 test models)Model page view 19, Hub API agent 50
Time per modelHub API agent, median 11.5 sMedian 9 ms, one graph query

All five models the Hub API agent wrongly called clean were quantized copies of merge trees, one with its CC BY-NC ancestor 9 hops up. The agent ran out of calls or hit a gated repo first. FinePrint walks the whole tree in one call.

How did FinePrint load 3.16M models into FalkorDB?

Dhiraj parsed the public cfahlgren1/hub-stats snapshot from October 18, 2026 with DuckDB. The FalkorDB bulk loader wrote the models and 927,431 typed lineage edges, FINETUNE_OF, ADAPTER_OF, MERGE_OF and QUANTIZED_FROM. Batched UNWIND and MERGE queries of 25,000 rows then set each model's effective license, which matters because 123,135 models hide the real license name behind the tag "other".

On top sit 47 License nodes linked to the Clause nodes they impose, each with a quote and source URL, plus 1,055,181 LICENSED_UNDER edges and 386,483 TRAINED_ON edges to 66,243 datasets. A full-text index brings search over 3.16M model ids to a median of 48 ms.

How does FinePrint find hidden license terms?

FinePrint · Dhiraj Kavuri · See the code · Use the app

Give FinePrint a model and how you plan to use it, and it answers ALLOW, CONDITIONS or BLOCK, with the clause and path behind the answer.

FinePrint demo
In the builder's words. "Answering that for one model is a few API calls. Answering it for the whole Hub is a graph problem, so I put the whole Hub in a graph." Dhiraj Kavuri, FinePrint

1. Mark every model below a restricted license

Lineage walks run inside FalkorDB as JavaScript UDFs. With merges, a variable-length match lists an exploding number of paths, while the UDF visits each model once. For the Hub-wide audit it starts from every restricted model at once. All 73,794 descendants of Qwen Research models take 0.4 seconds.

MATCH (r:Model) WHERE r.license IN $keys WITH collect(r) AS roots
RETURN lineage.descendantIds(roots)

With every model marked, the 48,975 headline is one count query that ran in 0.50 s.

MATCH (m:Model) WHERE size(m.inherits) > 0 AND m.license IN $permissive
RETURN count(m), sum(m.downloads)

2. Collect every clause a model inherits

One query walks the ancestors, follows each one's LICENSED_UNDER edge, and collects the clauses that license imposes. Each clause is a node with its quote and source, so the answer cites the license text.

MATCH (m:Model) WHERE m.id = $id
WITH lineage.ancestors(m, 64) AS anc
UNWIND anc AS a
MATCH (x:Model)-[:LICENSED_UNDER]->(l:License)-[:IMPOSES]->(c:Clause)
WHERE x.id = a.id AND l.permissive = false
WITH l, c, a ORDER BY a.depth
RETURN l.family, l.commercial, head(collect(a.id)) AS via, min(a.depth) AS depth,
       collect(DISTINCT c.obligation) AS obligations

For svara-tts-v1, GRAPH.PROFILE shows about 8 ms, mostly the ancestor walk.

3. Show the path, then decide and fail closed

FalkorDB's built-in algo.SPpaths returns the three shortest routes by which a restricted license reaches a model, and FinePrint draws that path on screen.

MATCH (s:Model), (t:Model) WHERE s.id = $s AND t.id = $t
CALL algo.SPpaths({sourceNode: s, targetNode: t,
                   relTypes: ['FINETUNE_OF','ADAPTER_OF','MERGE_OF','QUANTIZED_FROM'],
                   relDirection: 'outgoing', pathCount: 3})
YIELD path
RETURN [n IN nodes(path) | n.id], [r IN relationships(path) | type(r)]

Rules, not an LLM, turn this into a decision. A contractual non-commercial term means BLOCK for commercial use. Open obligations mean CONDITIONS. FinePrint fails closed. If part of the chain has no recognised license, the model declares no license, or its card names a base model that can't be resolved, the answer is never ALLOW. An LLM only adds evidence. For deepseek-ai/DeepSeek-R1-Distill-Llama-8B, which declares MIT and names no base model, it quotes the card ("derived from Llama3.1-8B-Base"), finds meta-llama/Llama-3.1-8B in the graph and writes a typed edge, and the verdict becomes CLOUDED. It never writes Cypher or decides a verdict.

Try it. Load your own lineage as typed edges and walk every ancestor with one query. Start free on FalkorDB Cloud.

What if FLUX.1-dev changed its license?

FinePrint keeps the 43,700-model FLUX.1-dev family in its own FalkorDB graph. Each what-if request runs GRAPH.COPY on it, relicenses FLUX.1-dev as Apache-2.0 on the copy, walks it again and deletes the copy, in 0.53 s. The answer is that 27,592 models would still be labelled non-commercial, because their own cards copied the FLUX.1 [dev] label.

The same FalkorDB instance holds a separate rulings graph per company, and the database user behind reports can run only GRAPH.RO_QUERY. Coding agents use it through FinePrint's MCP server, a download guard and a CLI that fails a CI build on a blocked model. In short, it is a context layer for AI agents.

Try it. Copy a graph with GRAPH.COPY, change one fact, and see everything downstream that moves. Start free on FalkorDB Cloud.

More from Graph Hacks: how teams built a company brain that traces every decision to its source, and how they used one graph to trace prompt injection and supply-chain attacks across AI agents.

Frequently asked questions

How do I check a Hugging Face model license?

Check the license on the model card, then follow the base model chain to every ancestor and check each one's license, because the model page shows only one hop. FinePrint does this with one query over a FalkorDB graph of all 3.16M public models and answers ALLOW, CONDITIONS or BLOCK, with the clause and path behind it.

Can a fine-tuned model declare a different license than its base model?

Uploaders can declare any license tag. FinePrint found 48,975 Hugging Face models that declare apache-2.0, MIT or another permissive license while a model they were built on carries restricted terms. These are differences between the declared license and upstream terms, so check the whole family tree before you ship.

Why use a graph database for model lineage?

License terms travel along a path of fine-tunes, adapters, merges and quantized copies, and a graph database walks that path in one query. FalkorDB returned all 21,639 descendants of Llama-3.1-8B in 70 ms, a walk that takes 21,653 Hugging Face API calls.

What does fail closed mean for a license checker?

A fail-closed checker never answers ALLOW when information is missing. FinePrint returns CONDITIONS when part of the lineage has no recognised license, the model has no license, or the card names a base model it cannot resolve. On sealed tests it called a restricted model clean 0 times out of 69.

How do I build a lineage graph on FalkorDB?

Load each item as a node and each derived-from link as a typed edge, then walk ancestors with Cypher or a UDF. Use FalkorDB's built-in graph algorithms, like algo.SPpaths for proof paths, and GRAPH.COPY to test what-if changes on a copy.

Trace what your data inherited

FinePrint runs on the same FalkorDB you can start with one Docker command, docker run -p 6379:6379 -p 3000:3000 -it --rm falkordb/falkordb:latest, or a free cloud instance. Load your lineage as typed edges, walk it in one query, and show the path behind every answer.

Start free on FalkorDB Cloud

Not ready to build yet? Join the FalkorDB Discord to get help from our engineers, share what you build, and hear about the next Graph Hacks first.

Author