SHACL: Validating Knowledge Graphs
A knowledge graph without validation is a rumour mill with an API. Everything you have learned so far lets you state and infer knowledge; none of it lets you reject bad data. SHACL, the W3C Shapes Constraint Language, is the layer that does, and it has quietly become the most operationally important standard in the stack: the gate in every serious ingestion pipeline, the contract between data producers and consumers, and, in the LLM era, the closed-world bouncer that keeps generated garbage out of governed graphs. Most of what ranks online for SHACL is a decade old and stops at toy examples. This lesson is the current, production-grade picture, through the SHACL 1.2 work landing now.

Shapes: constraints as data
SHACL’s core idea is that constraints are themselves RDF: you write a shapes graph describing what well-formed data looks like, a validator checks your data graph against it, and the output is a third graph, the validation report. Everything is triples, so shapes are versionable, queryable and publishable like any other data, and the report is machine-processable rather than a log file.
A node shape declares constraints on a class of nodes and how to find them, most commonly via sh:targetClass. A property shape, attached with sh:property, constrains one path from those nodes. In compact prose form: ex:PumpShape a sh:NodeShape ; sh:targetClass ex:Pump ; sh:property [ sh:path ex:ratedPowerKW ; sh:datatype xsd:decimal ; sh:minCount 1 ; sh:maxCount 1 ; sh:minInclusive 0 ] . Read it aloud and it is a data contract: every pump must state exactly one rated power, a non-negative decimal. The everyday constraint components cover cardinality (sh:minCount, sh:maxCount), datatypes and node kinds (sh:datatype, sh:nodeKind, so you can require an IRI rather than a blank node), value ranges (sh:minInclusive and friends), strings (sh:pattern for regex, sh:minLength, sh:languageIn for label policy), enumerations (sh:in), class membership of values (sh:class), and comparisons between paths (sh:lessThan, so a commissioning date precedes a decommissioning date). Logical combinators (sh:and, sh:or, sh:not, sh:xone) compose them, and sh:path accepts property paths, so a constraint can reach through ex:installedAt/ex:inRegion in one hop. When the built-ins run out, SHACL-SPARQL lets you express arbitrary conditions as a SPARQL query embedded in a constraint, which is why lesson 10 precedes this one: your query fluency is also your validation fluency. The normative definition of all of this is the W3C SHACL Recommendation.
Severity, targets and the report
Two design details make SHACL deployable rather than merely correct. First, severity: each shape carries sh:severity of sh:Violation, sh:Warning or sh:Info, so one shapes graph can express both hard contract (“reject the batch”) and style guidance (“flag for review”), and CI can branch on the difference. Second, precise targeting: beyond sh:targetClass you can target specific nodes, all subjects or objects of a property, or use SPARQL-based targets, so shapes bind to exactly the slice of graph they govern. The validation report then tells you, per failure, the focus node, the path, the value, the violated constraint component and the severity, which is everything a data steward needs to route the fix, and everything an automated repair loop needs to act.
SHACL versus OWL: the punchline of module 1
This is where lesson 4’s logic pays off in one table. OWL axioms describe how the world must be, under the open-world assumption, and drive inference. SHACL shapes describe how your dataset must look, right now, closed-world, and drive validation. The missing-customer example resolves cleanly: the OWL axiom infers an unknown customer exists; the SHACL shape with sh:minCount 1 reports a violation. Neither replaces the other, and mature systems run both against the same graph.
| Need | OWL behaviour (open world, inference) | SHACL behaviour (closed world, validation) |
|---|---|---|
| Every order has a customer | Infers an anonymous customer exists; no error raised | sh:minCount 1 raises a violation on the offending order |
| At most one rated power | Two stated values are inferred to be the same value; contradiction only if provably distinct | sh:maxCount 1 flags the node carrying two values |
| Value must match a pattern | Not expressible as a practical constraint | sh:pattern validates directly |
| Derive that a Margherita is a VegetarianPizza | Classification derives it from definitions | Out of scope; SHACL does not classify |
| Detect contradictory class membership | Consistency checking, given disjointness axioms | Expressible per-shape with sh:not, but reasoning is OWL’s job |
Worked example · the Aberdeen-2 asset register
Where we left it: the register answers questions but cannot yet refuse bad data. Lesson 4 promised a declared closed world at the report boundary; here it is.
ex:ValveShape a sh:NodeShape ;
sh:targetClass ex:Valve ;
sh:property [
sh:path ex:lastInspected ;
sh:datatype xsd:date ;
sh:minCount 1 ;
sh:severity sh:Violation ;
sh:message "No recorded inspection in the loaded sources." ;
] .
Run this when the compliance report is cut, and V-205 finally produces something actionable: a violation report naming the focus node, the missing path and the message, scoped to “the sources loaded now”. The same valve, in the same graph, where OWL rightly said “inspection unknown”, now yields “inspection missing, fix it”. Both are correct, because they answer different questions, which is the whole punchline of module 1. Meanwhile the PumpShape in the prose above closes lesson 10’s wound at the gate: sh:datatype xsd:decimal rejects the contractor’s string-valued “22.0” at ingestion, once, instead of every query defending itself forever.
State of the register: executable data quality, and a shapes file that doubles as the contract we hand the three source-system owners. The next three lessons make shapes derive data, not just reject it.
SHACL in CI: the highest-value habit in the stack
Treat shapes exactly as software teams treat tests. The shapes graph lives in version control beside the ontology; every pull request that touches data or mappings triggers validation; violations fail the build; severity separates blocking errors from advisories. Batch pipelines validate before merge into the governed store, so bad data is quarantined with its report attached rather than discovered downstream. Published shapes double as interface documentation: handing a supplier your SHACL file is handing them an executable specification of what you will accept, which converts data onboarding from email archaeology into red-and-green feedback. The instructor team’s own open-ontologies tooling is built around this philosophy, pairing SHACL gates with closed-world vocabulary checking so that a crosswalk or ontology release cannot ship while any check fails; lesson 27 builds the full testing and governance workflow on these foundations, and the running open ontologies course turns it into a complete certified-release practice.
The same loop is now the standard answer to LLM unreliability. The 2025-2026 extraction literature converged on one architecture: the model proposes triples, SHACL validates, the violation report is fed back into the prompt, and the model retries within a budget. OntoLogX (arXiv 2510.01409) applies exactly this iterative SHACL repair loop to knowledge graphs extracted from cybersecurity logs; a systematic study of LLM-driven knowledge graph repair (arXiv 2507.22419) evaluates how well models act on violation reports; xpSHACL (presented at the VLDB 2025 workshop on LLMs and graphs) generates human-readable explanations of violations with retrieval-augmented generation. The theory is moving too, with formal work on validation in the presence of ontologies (arXiv 2507.12286) and under graph updates (arXiv 2508.00137). The pattern generalises beyond extraction: whatever the neural component proposes, in module 6 you will see reasoners, tries and provers playing the same disposer role that SHACL plays here. Learn the loop once, reuse it everywhere.
What breaks · closing the shape “to be safe”
After the string-power incident, the data steward wants a fortress: no property on a pump unless the shape lists it.
ex:PumpShape sh:closed true ;
sh:ignoredProperties ( rdf:type ) .
It works for a fortnight. Then the engineering feed starts publishing ex:vibrationClass, a property nobody thought to pre-approve, and every pump on the platform fails validation at once. The batch quarantines, the dashboard goes red, and the on-call steward learns that closedness converts ordinary schema evolution into a violation storm. Two loads later the team sets the pipeline to warn-only “temporarily”, and the practice dies of alert fatigue, exactly the failure the adoption playbook warns about. Closed shapes are a legitimate tool with a narrow home: versioned, negotiated exchange contracts where unknown properties are themselves the defect. As the default posture for an integration graph that grows by design, sh:closed punishes the very extensibility that made RDF the right substrate in lesson 5.
SHACL 1.2: from validator to platform
After eight years of stability, SHACL is expanding. A rebooted W3C Data Shapes Working Group is producing the SHACL 1.2 family: SHACL 1.2 Core and SPARQL Extensions as the modernised base (First Public Working Drafts in 2025), plus, critically, SHACL 1.2 Rules (FPWD December 2025), which brings inference rules into shapes graphs, letting you derive new triples, not just validate existing ones, in the same standardised framework; Node Expressions (January 2026) as its computational substrate; and Profiling and User Interfaces drafts (2026), the latter pointing at shapes-driven form generation, where the same artifact that validates your data also renders its editing UI. The direction of travel is unmistakable: SHACL is absorbing territory once scattered across SPIN, custom rule engines and hand-built forms, and becoming the general-purpose declarative layer over RDF data. For working engineers the near-term guidance is simple: everything in this lesson’s core is stable and safe to standardise on today; track the Rules draft if you currently maintain a separate rules engine, because consolidation is coming.
Adoption playbook
Start narrow and real: pick the five data quality incidents that hurt most last quarter, write one shape per incident, and wire validation into the ingestion path with violations reported but not yet blocking. Tighten to blocking once the noise settles. Grow the shapes graph opportunistically, one shape per new incident, the same way good test suites grow one test per bug. Resist the urge to transliterate your whole ontology into shapes; shapes encode your operational contract, which is usually smaller than your conceptual model, and over-constrained shapes generate alert fatigue that kills the practice. Within a quarter you will have the artifact that distinguishes governed knowledge graphs from rumour mills: an executable, versioned, continuously enforced definition of what your organisation means by good data. The next three lessons take SHACL past validation and into inference, with SHACL Advanced Features: rules that can act on what is missing, the node expressions and custom targets that make them composable, and the provenance and testing discipline that keeps materialised inference honest.
Check yourself
The register runs this shape: target class ex:Pump; path ex:ratedPowerKW; sh:datatype xsd:decimal; sh:minCount 1; sh:maxCount 1. Which data snippet produces a violation?
- ex:P310 a ex:Pump .
- ex:P311 a ex:Pump ; ex:ratedPowerKW 12.5 ; ex:ratedPowerKW 12.5 .
- ex:C7 a ex:Compressor ; ex:ratedPowerKW “high” .
- ex:P101 a ex:Pump ; ex:ratedPowerKW 18.5 .
Show the answer, and why each wrong option is wrong
A is correct. P-310 is targeted (it is a Pump) and has no rated power at all, so sh:minCount 1 fires. Contrast the OWL reading one last time: the equivalent axiom would have inferred that an unknown rated power exists and reported nothing. That contrast is module 1’s entire argument compressed into one violation.
B looks like a maxCount violation, but RDF graphs are sets of triples: writing the identical triple twice yields one triple, so P-311 has exactly one value and conforms. It would take two different values to breach maxCount. C contains genuinely bad data, a string where a decimal belongs, and passes anyway, because validation only inspects what the target selects and C7 is not a Pump. Untargeted garbage is invisible; broadening targets is lesson 13’s subject. D conforms; it is the shape’s happy path from lesson 5.

