What’s Changed & Migration
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. The reference material consulted while preparing these pages is listed in the section bibliography. |
Baseline date: 2026-10-13. This page was written against Apache Tika 4.1.0 (released 29 September 2026, still the latest
release on the baseline date) and the 3.x maintenance line (3.3.2, released 16 July 2026), Java 21 for the examples (Tika
4.x needs Java 17 or later, 3.x needs Java 11), Spring Boot 4.x on Spring Framework 7 and the Docker image
apache/tika:4.1.0. Every other page of this section ends with a short "1.x to 4.x" table for its own topic; this page
collects them into one place. It gives the release timeline and the support window of every line, walks through what
each major version changed, lists the vulnerabilities that make an upgrade urgent, and maps the idioms of Tika in
Action (written for Tika 1.0 in 2011) to the code that replaces them. It ends with a complete migration of the
Bookshelf intake program and an ordered checklist for moving a 3.x application to 4.1.
The page is a hub, not a replacement for the topic pages. Each row of each table links to the page that explains the
change in depth: Configuration for tika-config.json,
Metadata for the tk: keys,
Tika Server (REST API) for the server,
Tika App (Command Line & GUI) for the command line and
Robustness, Limits & Timeouts for the timeout model.
Version timeline
The dates are the announcement dates of the Apache Tika news page, which can be a few days after the artifacts reached
Maven Central (the tika-core 3.0.0 POM is dated 16 October 2024, the announcement 19 October 2024). The two 3.x
end-of-support entries are not a typo: the sources disagree, as explained below.
| Release | Announced | Java | What it is remembered for |
|---|---|---|---|
1.0 |
7 November 2011 |
5 |
The first 1.x release, the one Tika in Action was written for. It removed the pre-1.0 deprecated APIs and the JDK 1.4 build. |
1.28.5 |
14 September 2022 |
8 |
The last 1.x release, a security fix. |
2.0.0 |
19 July 2021 |
8 |
Parser modules split out of |
2.9.4 |
5 May 2025 |
8 |
The final 2.x release; the announcement marked 2.x and Java 8 support as end of life. |
3.0.0 |
19 October 2024 |
11 |
Java 11, jakarta namespaces, PDFBox 3, JSoup-based HTML parsing, tika-grpc (first in 3.0.0-BETA2). |
3.3.0 |
23 March 2026 |
11 |
|
3.3.2 |
16 July 2026 |
11 |
SAX-based OOXML parsers ported from 4.x and made the default; |
4.0.0-alpha-1 |
8 May 2026 |
17 |
The first 4.x preview: a large refactoring with breaking changes. |
4.0.0-beta-1 |
3 July 2026 |
17 |
Markdown default, zip distributions, pf4j pipes plugins; fixes CVE-2026-66755 and CVE-2026-66756 for the 4.x line. |
4.0.0 |
21 August 2026 |
17 |
First stable 4.x: forked, crash-isolated parsing everywhere, JSON configuration, |
4.1.0 |
29 September 2026 |
17 |
|
Source: Apache Tika, home page news (dates and release highlights),
tika-core versions on Maven Central
and CHANGES-3.0.0.txt.
Is there a 4.2?
Not on the baseline date. The checks made on 2026-10-13:
-
Maven Central
tika-corelists4.1.0as the latest release (lastUpdated29 September 2026); the versions after 3.3.2 are4.0.0-alpha-1,4.0.0-beta-1,4.0.0and4.1.0. -
The Apache download area (
dlcdn.apache.org/tika/) holds3.3.2/and4.1.0/only. -
Docker Hub has
4.2.0-SNAPSHOTand4.2.0-SNAPSHOT-fulltags (nightly builds of the development branch) next to the released4.1.0,4.1.0-1,4.1.0-full,4.1.0-1-full,latestandlatest-full. Never deploy aSNAPSHOTtag. -
The Git repository has a
3.3.3-rc1tag, a release candidate, but no 3.3.3 release was announced or published. -
The 4.1.0 announcement says the project plans to change the default unpack format to Frictionless in 4.2.0 and asks users who would be affected to say so on the dev list. If you extract embedded files with
-z,/unpackorParseMode.UNPACK, set the format explicitly now so that the 4.2 default cannot surprise you (see Embedded Documents & Recursive Parsing).
Support windows
| Line | Latest | Java | Namespace | Status on 2026-10-13 |
|---|---|---|---|---|
4.x |
4.1.0 |
17 |
jakarta |
Active development. The line to choose for new work. |
3.x |
3.3.2 |
11 |
jakarta |
Maintenance: bug fixes and dependency upgrades. End of support in early 2027 (see below). |
2.x |
2.9.4 |
8 |
javax |
End of life since April 2025 (final release May 2025). No fixes. |
1.x |
1.28.5 |
8 |
javax |
End of life since 30 September 2022. No fixes. |
The 3.x end-of-support date
Two official pages give different dates, and neither has been corrected since 4.0.0 shipped:
-
The roadmap page of the 4.1.x documentation has a version-support table that lists 3.x as supported until March 2027. The same page still says "Only 2.x and 3.x have shipped" and lists 4.x as "not yet released (4.0.0 in progress)", so it was written before 4.0.0 and is stale in at least that respect.
-
The Tika wiki roadmap ("Tika Roadmap — 2.x, 3.x and Beyond", last updated 21 July 2026) gives the planned end of life of 3.x as "January 2027 or 6 months after the release of 4.0.0, whichever comes first". With 4.0.0 announced on 21 August 2026, six months after it is late February 2027, so the rule resolves to January 2027. The same page also keeps an older timeline line that said June 2026.
-
The home page and the download page only say that the 3.x maintenance line "remains supported".
The safe reading is that 3.x support ends some time between January and March 2027, and that every new 3.x release
could be the last. Plan the move to 4.x now; use 3.x only while a dependency or a Java 11 runtime forces you to. Re-check
both pages before committing to a date, and watch the announce@apache.org list for the end-of-life notice, as the
project published one for 1.x and 2.x.
Security fixes that force an upgrade
A version line is only as good as its last security fix. Four CVE records published in the last two years decide the minimum versions to run. The two 2026 records are recent enough that Tika’s own security page did not list them on the baseline date; they were checked in the CVE records themselves.
| CVE | Published | Issue | Affected, and the first fixed version |
|---|---|---|---|
2025-08-20 |
Critical XML external entity (XXE) injection through a crafted XFA form inside a PDF. |
|
|
2025-12-04 |
The same XXE, with a wider scope: the vulnerable code path is also in |
|
|
2026-07-30 |
"Arbitrary Local File Read in ISArchiveParser": relative path traversal in the ISA-Tab parser. A "Study Assay File Name" value in an ISA-Tab investigation file can point outside the dataset directory, and Tika then reads that file into the extracted text. It needs an attacker who can place files in a directory the application later parses. CVSS 4.0 base score 5.9 (medium), local attack vector. |
|
|
2026-07-30 |
"unpack endpoint in tika-server allows configuration with unsecureFeatures=false", classified as improper protection of an alternate path: the |
|
What this means for an upgrade plan:
-
Anything at or below 3.2.1 is exposed to a critical XXE through ordinary PDF files. That includes every 1.x and 2.x release, which will never receive a fix: their only remedy is a migration.
-
On 3.x, run 3.3.2. It is the first 3.x release that fixes CVE-2026-66755. The ISA-Tab parser lives in
tika-parser-scientific-module, whichtika-parsers-standard-packagedoes not include (since 2.0 the scientific parsers are a separate, optional package), so check withmvn dependency:treewhether your build pulls it in. -
Never run 4.0.0-alpha-1, a preview that is affected by both 2026 records. 4.0.0 and 4.1.0 are not affected.
-
Upgrade every Tika artifact together, from the BOM. CVE-2025-66516 exists because patching one module left the vulnerable code in another.
The CVE pages were checked through the CVE Services API (cveawg.mitre.org/api/cve/<id>), which serves the records
that cve.org displays; the titles, affected ranges and CVSS scores above are quoted from those records. The full CVE
history, grouped by the lesson each one teaches, is on Security.
Source: the CVE records linked in the table (retrieved 2026-10-13), the Apache announcements they reference (CVE-2026-66755 and CVE-2026-66756) and Apache Tika, Security.
1.x: the Tika of the book
Tika in Action by Chris A. Mattmann and Jukka L. Zitting (Manning, 2011) describes Tika 1.0. Its model is still the model of Tika 4.1, which is why the book remains worth reading:
-
Detection combines magic bytes, file-name globs, XML root elements and container inspection, organised in a media type registry with a type hierarchy (chapters 4 and 11).
-
A
Parserturns a stream into XHTML SAX events plus aMetadataobject;AutoDetectParserchooses the parser; aContentHandlerdecides what to keep (chapter 5). -
Metadata is a multi-valued map with keys drawn from standards such as Dublin Core (chapter 6).
-
Language identification uses character n-gram profiles (chapter 7).
-
Robustness means running parsers out of process (
ForkParser, chapter 9).
What changed is everything around that model. The 1.x line kept going for eleven years after the book, ending with
1.28.5 in September 2022. By then it had added tika-server, RecursiveParserWrapper and the X-TIKA: metadata keys,
and later 1.x releases required Java 8. The PMC set 30 September 2022 as the end of life of 1.x and stopped making
security fixes after that date.
A 1.x application still in production has two problems at once: it is exposed to CVE-2025-54988 and CVE-2025-66516
(tika-parsers 1.13 to 1.28.5), and it is three API generations behind. Migrate it in one jump to 4.1, using the idiom
table further down; there is no benefit in stopping at 2.x or 3.x on the way.
Source: Apache Tika, home page news (the 1.0, 1.28.5 and 1.x end-of-life entries) and Tika in Action, chapters 4 to 7, 9 and 11.
2.0: modules, Pipes and cleaner metadata
Tika 2.0.0 (July 2021) was the first big break. The official "Migrating to Tika 2.0.0" wiki page lists these major changes:
-
The parsers were split into modules. The single 1.x
tika-parsersartifact became one module per format family (tika-parser-pdf-module,tika-parser-microsoft-moduleand so on) and packages that group them:tika-parsers-standard-package, plus optionaltika-parser-scientific-packageandtika-parser-sqlite3-package(andtika-parser-nlp-packagefrom 2.7.0). Container detection (.doc,.docx,.xlsx) needs the standard package, because it is the parsers that look inside the container. -
Metadata was cleaned up. Deprecated keys and the duplicate and triplicate keys of early 1.x were removed. For example
Author,meta:authoranddc:creatorcollapsed todc:creator, andtitleanddc:titletodc:title. Some Java constants moved:Metadata.RESOURCE_NAME_KEYbecameTikaCoreProperties.RESOURCE_NAME_KEY, andTikaCoreProperties.KEYWORDSwas removed in favour ofOffice.KEYWORDS.X-Parsed-BybecameX-TIKA:Parsed-By. -
Language detection became an SPI. The 1.x
LanguageIdentifierwas removed; detectors implementLanguageDetectorand live intika-langdetect-*modules (Optimaize was the usual choice in 2.x and 3.x). -
tika-server became
tika-server-standard, with the standard parsers only, and ran in--spawnChildmode by default: a watchdog parent restarted a child process that crashed or hung. -
Configuration moved to
tika-config.xml. The.propertiesfiles of the PDF, Tesseract and strings parsers were dropped; parsers are configured when they are instantiated. -
Tika Pipes arrived:
PipesClientandPipesServer, fetchers, emitters and pipes iterators. -
OCR became automatic for PDFs when Tesseract is on the path, which surprised users who then had to switch it off.
-
Logging moved from Log4j 1 to Log4j 2 in tika-app and tika-server (2.0.0-BETA to 2.1.0 were affected by Log4Shell, CVE-2021-44228, through that dependency; upgrade past 2.2.1).
Source: Tika wiki, Migrating to Tika 2.0.0 and Apache Tika, Security (Log4j entries).
2.x build files
The dependency change is the first thing a 1.x project hits. The 1.x artifact (shown only for recognition):
<!-- Tika 1.x only: one artifact with every parser -->
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-parsers</artifactId>
<version>1.28.5</version>
</dependency>
The 2.x and 3.x equivalent named the standard package as a jar. In 4.x the same coordinates are a pom (see
Build files for 4.x), so a 2.x or 3.x build file needs one more edit when it moves to 4.x.
Source: Tika wiki, Migrating to Tika 2.0.0.
3.0: Java 11, jakarta and PDFBox 3
Tika 3.0.0 (October 2024) was mostly a platform release. There is no official 2.x to 3.x migration page; the list below comes from the 3.0.0 change log (which lists the BETA, BETA2 and final releases) and the roadmap.
-
Java 11 is required (TIKA-4128), and the 3.x line uses the
jakartanamespaces where 2.x usedjavax(per the version table of the roadmap page). -
PDFBox 3 replaced PDFBox 2 (TIKA-3347). Applications that also use PDFBox directly must move to 3.x with it; see PDF Parsing.
-
HTML parsing moved from TagSoup to JSoup (TIKA-1599). A custom configuration of
HtmlParserhas to nameorg.apache.tika.parser.html.JSoupParserinstead. -
custom-mimetypes.xmlis looked up at the classpath root, no longer under/org/apache/tika/mime/(TIKA-4147). -
JavaScript is reported as
text/javascriptinstead ofapplication/javascript, following RFC 9239 (TIKA-4119). -
The boilerpipe handler moved to its own
tika-handler-boilerpipepackage (TIKA-4138), and Xerces 2 was dropped as a dependency (TIKA-4135). -
AbstractParserwas deprecated for removal in 4.x (TIKA-4132): implementParserdirectly. -
tika-grpc was added in 3.0.0-BETA2 (TIKA-4181); see Tika gRPC.
-
Convenience methods for XML readers moved from
ParseContexttoXMLReaderUtils(TIKA-4259).
Later 3.x minor releases changed behaviour too, which matters when you compare a 3.x baseline with 4.x output: 3.2.2 fixed
the XFA XXE, 3.3.0 moved to poi-ooxml-full, and 3.3.2 made the SAX-based OOXML parsers the default and put /pipes,
/async and /status behind enableUnsecureFeatures=true. Compare 4.x output with 3.3.2 output, not with an older 3.x.
Source: CHANGES-3.0.0.txt, Apache Tika 4.1.x, Roadmap and Apache Tika, home page news (3.2.2 to 3.3.2 entries).
4.0 and 4.1: the biggest break since 2.0
Tika 4.0.0 (21 August 2026) changed the platform, the packaging, the configuration format, the core SPI, the default output, the metadata keys and the server, all at once. The official "notable changes" page groups the breaking changes; this section follows the same grouping and links each item to the page of this section that covers it.
Platform and packaging
-
Java 17 or later (3.x ran on Java 11).
-
Zip distributions.
tika-appandtika-server-standardship as zips whose jar is a thin launcher next tolib/andplugins/. The bare jar fails withNoClassDefFoundError. This catchestika-server-standardhardest, because its jar is still on Maven Central. Container images and scripts that copied only the jar must unzip the distribution instead; see Setup & Installation and Docker & Kubernetes Deployment. -
tika-parsers-standard-packageis apom: Maven needs<type>pom</type>, Gradle@pom. -
Release channels split. Maven Central has slim per-module jars, the Apache download area the runnable zips and the pf4j plugin zips, Docker Hub the images.
-
Modules removed with no direct replacement:
tika-batch(and the-bcbatch mode of tika-app),tika-dl, the advanced media module,tika-fuzzing,tika-age-recogniser,tika-server-eval, the .NET bindings and the snap packages. The oldtika-langdetect-tikamodule was removed too, and CharSoup became the bundled language detector.
Configuration
-
JSON replaces XML.
TikaConfigand the XML configuration API are removed;TikaLoaderfromtika-serializationloadstika-config.json. Components are referenced by registered names (pdf-parser), not class names. -
tika-app --convert-config-xml-to-jsonconverts theparserssection of a 3.x file; every other section is a manual rewrite. See Configuration. -
Parsers and detectors no longer expose bean setters for their settings; options live in per-component config objects passed through the
ParseContext(TIKA-4758).
Java API
-
TikaInputStreamin the SPI.Parser.parsetakes aTikaInputStream;Detector.detecttakes(TikaInputStream, Metadata, ParseContext);EmbeddedDocumentExtractormethods gain aParseContext. Every third-party parser, detector and extractor must be updated, and the break is a compile error, not a silent change. TheTikafacade still accepts anInputStream, butTika.detect(InputStream)no longer returns the caller’s stream at its original position. See Parser API & AutoDetectParser. -
No implicit spooling. A
TikaInputStreamis consumed in passthrough mode unlessenableRewind()is called at position 0;rewind(),getFile()orgetPath()after reading without it throw instead of spooling to disk. -
Unified timeout model. A total-task budget plus a progress (stall) timeout, shared by the library, tika-app, Pipes and the server.
TikaTimeoutExceptionis now a checked exception, and*TimeoutSeconds/*TimeoutMssettings became*TimeoutMillis. See Robustness, Limits & Timeouts. -
ForkParserand the wholeorg.apache.tika.forkpackage are removed;PipesForkParser(moduletika-pipes-fork-parser) replaces them. -
Encoding detectors moved to
org.apache.tika.detect.*and newtika-encoding-detector-*modules, with a new default pipeline; see Character Encoding Detection. -
EmbeddedDocumentExtractoris stateless, and the extractor factories (EmbeddedDocumentExtractorFactoryand friends) were deleted; bind an extractor instance in theParseContext. See Embedded Documents & Recursive Parsing. -
ExternalParseris configuration-only:CompositeExternalParser,ExternalParsersFactoryand the XML auto-discovery are gone; each external tool is an explicit JSON entry. See Extending Tika. -
Other removals:
Metadata#setAll(Properties)(useputAll(Metadata)),TikaMimeKeys,CreativeCommons, the DOM-based OOXML extractors,ParserUtils.EMBEDDED_PARSER,TikaCoreProperties.TIKA_CONTENT_HANDLER(useTIKA_CONTENT_HANDLER_TYPE), the...ChoisemisspelledPropertyfactories (renamed to...Choice), and thewritefilterpackage (renamedwritelimiter).
Output
-
Markdown is the default content format for tika-app, tika-server (
/tika,/rmeta) and the pipes CLI. Ask for XHTML with-x,/tika/xmlor/rmeta/xml. See Content Handlers & Output Formats. -
Metadata keys moved to the
tk:namespace in kebab-case (tk:resource-name,tk:parsed-by,tk:content), replacingX-TIKA:,tika:,tika_pg:,rendering:,signature:,imagereader:and bare names such asresourceName.TikaCorePropertiesconstants keep compiling. The opt-inlegacy-key-migration-filterrestores 3.x spellings at the emit edge. String-keyed writes to reserved keys now throw.Metadatano longer implementsHttpHeaders,Message,TIFFand the other constant interfaces, soMetadata.CONTENT_TYPEbecomesHttpHeaders.CONTENT_TYPE. See Metadata.
Services
-
tika-server parses in forked JVMs through Tika Pipes, always.
numClientsis both the concurrency ceiling and the memory footprint; each fork’s heap is set withpipes.forkedJvmArgs. -
enableUnsecureFeaturesis gone (a config that still has it fails to start) and is split intoallowPipesandallowPerRequestConfig, both default-deny. -
Accurate status codes:
429when every fork is busy,503when a fork crashed, timed out or ran out of memory,400for unknown fetchers and handlers,413for oversized bodies. Error bodies are JSON. -
Endpoints removed or merged:
/translate/*,/tika/main, the/tika/formfamily;/detect/streamis/detect;/language/streamand/language/stringare/language. TheAcceptheader no longer selects the output format. -
Per-request configuration headers removed (
writeLimit,X-Tika-Handler,meta_*,X-Tika-OCR*,X-Tika-PDF*) and silently ignored if sent. -
taskTimeoutMillisbecameparse-context.timeout-limits.totalTaskTimeoutMillis, and its default grew from 5 minutes to 1 hour. No startup error flags this one. -
tika-grpc’s generated Java classes moved to
org.apache.tika.pipes.grpc.proto; the wire protocol did not change.
The full server delta, with the 3.x XML and the 4.x JSON side by side, is on Tika Server (REST API); the command line delta is on Tika App (Command Line & GUI); gRPC is on Tika gRPC.
New in 4.0
-
Vision-language-model parsers (Claude, Gemini, OpenAI-compatible) in
tika-vlmand thetika-inferencemodule; see VLM Parsers & Inference. -
In-process Tesseract through
tika-parser-tess4j-module; see OCR with Tesseract. -
Pipes parse modes
NO_PARSE,CONTENT_ONLYandUNPACK, and new pipes plugins (Elasticsearch emitter, Google Drive, Microsoft Graph, Azure Blob, JSON, HTTP, Atlassian JWT, an Ignite config store); see Tika Pipes. -
Small documents travel to the fork inside the request (
pipes.maxInlineBytes, 10 MB by default) instead of through a temporary file. -
A Markdown parser with structured XHTML output, unified XMP extraction (HEIF, WebP, motion photos), content-based detection of PKCS#7, PKCS#12 and timestamped-data containers (files that were
application/octet-streamin 3.x may now get a crypto type), and audio cover art as embedded documents (embedded counts for audio files change). -
tika.extras.dirto load extra jars into tika-app and tika-server without repackaging (a trusted code location). -
Rewritten charset, junk-text and language detection, with CharSoup as the bundled language detector; see Language Detection & Translation.
-
Dependency jumps such as Jetty 11 to 12.1, CXF 4.0 to 4.2 and SolrJ 8.11 to 10.0.
What 4.1 changed over 4.0
4.1.0 is a minor release, but it has its own "Breaking Changes and Deprecations" list. Read it before moving from 4.0:
| Change | Effect on an upgrade from 4.0 |
|---|---|
OCR and enrichment engines are selected by name in a |
The |
PDF page settings become the |
Move per-page rendering and OCR options of the PDF parser there; see PDF Parsing. |
|
|
Pipes IPC carries inline bytes as a raw binary field (TIKA-4829) |
4.0.0 tuples with an |
Pipes plugins no longer bundle Jackson (TIKA-4840) |
Plugin configuration is parsed by a strict shared mapper that rejects unknown and duplicate keys. |
|
Configure it explicitly. |
Temp files follow |
|
Kafka pipes iterator (TIKA-4833) |
No longer stops on the first empty poll; |
|
Secrets no longer need to be written into the file. |
Server presets (TIKA-4856) and Micrometer metrics (TIKA-4839) |
New, opt-in. |
With a |
Detection results can change for callers that pass an override. |
|
In 4.0.0 they were silently dropped. |
|
In 4.0.0 values above 1 stopped one level early. |
|
Still experimental: classes, keys and output may change in minor releases. |
Outdated idiom to current code
The table maps the idioms of Tika in Action to their Tika 4.1 form. The book was written for Tika 1.0; its listings are grouped here by the idiom they use rather than reproduced, and the chapter is the one that introduces the idiom. Rows marked "verified" were compiled (and, where they produce output, run) against Tika 4.1.0 for this page; the others cite the page that verified them.
| Ch. | Book-era idiom (1.x) | Current code (4.1) | Notes |
|---|---|---|---|
Facade and command line |
|||
1, 3 |
|
Unchanged: |
Verified. Still runs in your JVM: fine for trusted files, not for hostile input. Default limit 100,000 characters. |
3 |
|
|
|
3 |
|
|
4.x returns the caller’s stream advanced. |
2 |
|
Run |
|
2 |
|
Unzip |
The bare 4.x jar fails with |
2 |
|
|
Markdown default since 4.0. |
Media types and detection |
|||
4 |
|
|
Verified (both exist in 4.1.0). |
4 |
|
|
Verified. |
4 |
|
|
Verified. The key is written as |
11 |
|
|
Changed in 3.0 (TIKA-4147). See Media Types & Detection. |
4 |
ICU4J |
|
ICU4J and juniversalchardet are optional modules in 4.x. See Character Encoding Detection. |
Parsing and content handlers |
|||
5 |
|
Wrap first: |
Verified. There is no |
5 |
|
|
Verified. |
5 |
|
|
The 100,000-character default is silent truncation. |
5 |
|
|
|
5 |
|
Unchanged classes |
Verified (present in 4.1.0). |
5 |
|
|
No implicit spooling since 4.0. |
Metadata |
|||
6 |
|
|
Verified. The 1.x string constants were deprecated in 1.x and removed by 2.0. |
6 |
|
|
|
6 |
|
|
Verified: the old form fails with "cannot find symbol: variable CONTENT_TYPE". |
6 |
String keys such as |
|
Use constants, not strings. Old consumers: |
6 |
|
|
Writing a reserved |
Embedded documents |
|||
5, 8 |
|
|
Verified. |
8 |
A custom |
A stateless extractor bound in the |
The extractor factories were deleted in 4.0. |
Language |
|||
7 |
|
|
Verified. Codes are ISO 639-3 ( |
7 |
|
|
Removed in 2.0. |
Robustness and scale |
|||
9 |
|
|
Verified. |
9 |
One |
Same sharing rule, but untrusted files go to |
In-process denial of service is not a vulnerability under the security model. |
9 |
Your own thread pool and directory loop (later |
Tika Pipes: a file-system iterator, fetcher and emitter, or |
|
Configuration and extension |
|||
11 |
|
|
Verified. XML is not read at all. |
11 |
|
|
Component names, not class names. |
11 |
|
|
|
11 |
|
An explicit |
Auto-discovery removed in 4.0. |
Integration |
|||
10 |
Lucene 3 |
|
The Lucene 3 field API is gone. See Search Indexing with Lucene, Solr & Elasticsearch. |
12 to 15 |
Case studies (Nutch, Jackrabbit, OODT and others) embedding Tika in-process |
Read them as history; current integrations are Solr Cell, the Elasticsearch attachment processor, Pipes emitters and RAG loaders |
See RAG & LLM Ingestion. |
The 1.x column describes the idiom; the book’s own listings are not reproduced. The chapter numbers and the individual listing numbers were not re-checked against a copy of the book for this page.
Source: Apache Tika 4.1.x, Migrating to Tika 4.x, Tika wiki, Migrating to Tika 2.0.0, Apache Tika 4.1.0 Javadoc and Tika in Action, chapters 1 to 15.
A complete migration: the Bookshelf intake
The Bookshelf intake service detects a renamed file, extracts text and metadata from a manuscript, identifies the language of a review, walks the attachments of a publisher e-mail and isolates PDF parsing in a separate process. The three listings below do the same job in the style of the book, of 3.x and of 4.1.
The book-era version (1.x, do not use)
Written for this page in the style of Tika in Action; it does not compile against any current Tika and was not run.
// Tika 1.x style. Every marked line is removed or changed in later versions.
TikaConfig config = new TikaConfig(new File("tika-config.xml")); // 4.0: TikaLoader
Parser parser = new AutoDetectParser(config);
Metadata metadata = new Metadata();
metadata.set(Metadata.RESOURCE_NAME_KEY, "manuscript.docx"); // 2.0: TikaCoreProperties
InputStream stream = new FileInputStream("manuscript.docx"); // no try-with-resources
ContentHandler handler = new BodyContentHandler(); // silent 100,000 limit
ParseContext context = new ParseContext();
context.set(Parser.class, parser); // attachments merged into one text
parser.parse(stream, handler, metadata, context); // 4.0: TikaInputStream
System.out.println(metadata.get(Metadata.TITLE)); // 2.0: removed
System.out.println(metadata.get(Metadata.CONTENT_TYPE)); // 4.0: HttpHeaders
LanguageIdentifier identifier = new LanguageIdentifier(handler.toString()); // 2.0: removed
System.out.println(identifier.getLanguage()); // "es", not "spa"
ForkParser fork = new ForkParser(getClass().getClassLoader(), parser); // 4.0: removed
The 3.x version
Shown for readers migrating a 3.x code base. It compiles against 3.3.2 in shape but was not built for this page.
// Tika 3.x only.
TikaConfig config = new TikaConfig(Path.of("tika-config.xml"));
Parser parser = new AutoDetectParser(config);
Metadata metadata = new Metadata();
try (InputStream stream = Files.newInputStream(Path.of("manuscript.docx"))) {
parser.parse(stream, new BodyContentHandler(1_000_000), metadata, new ParseContext());
}
System.out.println(metadata.get(TikaCoreProperties.TITLE));
System.out.println(metadata.get(Metadata.CONTENT_TYPE)); // still inherited in 3.x
System.out.println(metadata.get("X-TIKA:Parsed-By")); // string key, renamed in 4.0
LanguageDetector detector = new OptimaizeLangDetector().loadModels(); // tika-langdetect-optimaize
System.out.println(detector.detect(text).getLanguage());
ForkParser fork = new ForkParser(MyApp.class.getClassLoader(), parser); // removed in 4.0
The 4.1 version
The same work with current APIs. Dependencies: tika-core, tika-parsers-standard-package (as a pom),
tika-serialization and tika-pipes-fork-parser, all 4.1.0 from tika-bom.
tika-config.json, next to the sample files:
{
"parsers": [
{ "default-parser": {} }
],
"parse-context": {
"output-limits": {
"writeLimit": 1000000,
"throwOnWriteLimit": false
},
"embedded-limits": {
"maxDepth": 5,
"maxCount": 100
}
}
}
import java.nio.file.Path;
import java.util.List;
import org.apache.tika.Tika;
import org.apache.tika.config.loader.TikaLoader;
import org.apache.tika.io.TikaInputStream;
import org.apache.tika.language.detect.LanguageDetector;
import org.apache.tika.language.detect.LanguageResult;
import org.apache.tika.metadata.HttpHeaders;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.metadata.TikaCoreProperties;
import org.apache.tika.parser.ParseContext;
import org.apache.tika.parser.Parser;
import org.apache.tika.parser.RecursiveParserWrapper;
import org.apache.tika.pipes.fork.PipesForkParser;
import org.apache.tika.pipes.fork.PipesForkParserConfig;
import org.apache.tika.pipes.fork.PipesForkResult;
import org.apache.tika.sax.BasicContentHandlerFactory;
import org.apache.tika.sax.BodyContentHandler;
import org.apache.tika.sax.RecursiveParserWrapperHandler;
/** The Bookshelf intake idioms of the book, rewritten for Tika 4.1. */
public class MigratedIntake {
public static void main(String[] args) throws Exception {
Path inbox = Path.of(args.length > 0 ? args[0] : ".");
// 1. Configuration: TikaLoader and tika-config.json replace TikaConfig and tika-config.xml.
TikaLoader loader = TikaLoader.load(inbox.resolve("tika-config.json"));
Parser parser = loader.loadAutoDetectParser();
// 2. Detection by content: the facade still accepts a Path.
Tika tika = new Tika();
System.out.println("detect renamed-invoice.png -> " + tika.detect(inbox.resolve("renamed-invoice.png")));
// 3. Parsing: a TikaInputStream, an explicit write limit and typed metadata keys.
Metadata metadata = new Metadata();
BodyContentHandler handler = new BodyContentHandler(1_000_000);
try (TikaInputStream tis = TikaInputStream.get(inbox.resolve("manuscript.docx"))) {
parser.parse(tis, handler, metadata, loader.loadParseContext());
}
System.out.println("parse " + HttpHeaders.CONTENT_TYPE + " = " + metadata.get(HttpHeaders.CONTENT_TYPE));
System.out.println("parse " + TikaCoreProperties.TITLE.getName() + " = " + metadata.get(TikaCoreProperties.TITLE));
System.out.println("parse " + TikaCoreProperties.CREATOR.getName() + " = " + metadata.get(TikaCoreProperties.CREATOR));
System.out.println("parse " + TikaCoreProperties.TIKA_PARSED_BY.getName() + " = "
+ String.join(", ", metadata.getValues(TikaCoreProperties.TIKA_PARSED_BY)));
// 4. Language: the LanguageDetector SPI replaces LanguageIdentifier.
String review = tika.parseToString(inbox.resolve("reviews-es.html"));
LanguageDetector detector = LanguageDetector.getDefaultLanguageDetector().loadModels();
LanguageResult language = detector.detect(review);
System.out.println("language reviews-es.html -> " + language.getLanguage() + " " + language.getConfidence());
// 5. Embedded documents: RecursiveParserWrapper replaces context.set(Parser.class, parser).
RecursiveParserWrapper wrapper = new RecursiveParserWrapper(parser);
RecursiveParserWrapperHandler rpw = new RecursiveParserWrapperHandler(
new BasicContentHandlerFactory(BasicContentHandlerFactory.HANDLER_TYPE.TEXT, 100_000));
try (TikaInputStream tis = TikaInputStream.get(inbox.resolve("publisher-email.eml"))) {
wrapper.parse(tis, rpw, new Metadata(), new ParseContext());
}
List<Metadata> list = rpw.getMetadataList();
for (Metadata m : list) {
String path = m.get(TikaCoreProperties.EMBEDDED_RESOURCE_PATH);
System.out.println("embedded " + (path == null ? "(container)" : path) + " " + m.get(HttpHeaders.CONTENT_TYPE));
}
// 6. Crash isolation: PipesForkParser replaces ForkParser.
try (PipesForkParser forked = new PipesForkParser(new PipesForkParserConfig().addJvmArg("-Xmx512m"));
TikaInputStream tis = TikaInputStream.get(inbox.resolve("catalogue.pdf"))) {
PipesForkResult result = forked.parse(tis);
System.out.println("forked catalogue.pdf -> " + result.getStatus() + ", "
+ result.getContent().strip().lines().findFirst().orElse(""));
}
}
}
Output (Tika 4.1.0, Java 21; log lines on standard error omitted):
detect renamed-invoice.png -> application/pdf
parse Content-Type = application/vnd.openxmlformats-officedocument.wordprocessingml.document
parse dc:title = The Lighthouse Keeper
parse dc:creator = Ana Torres
parse tk:parsed-by = org.apache.tika.parser.DefaultParser, org.apache.tika.parser.microsoft.ooxml.OOXMLParser, org.apache.tika.parser.microsoft.ooxml.xwpf.XWPFEventBasedWordExtractor
language reviews-es.html -> spa MEDIUM
embedded (container) message/rfc822
embedded /samples.zip/chapter-one.docx/figure1.png image/png
embedded /samples.zip/chapter-one.docx application/vnd.openxmlformats-officedocument.wordprocessingml.document
embedded /samples.zip/catalogue.pdf application/pdf
embedded /samples.zip/cover-note.txt text/plain; charset=windows-1252
embedded /samples.zip application/zip
forked catalogue.pdf -> PARSE_SUCCESS, Spring catalogue
What the output shows about the migration:
-
The keys printed by name are the 4.x names:
dc:titleanddc:creatorare unchanged since 2.0,tk:parsed-byisX-TIKA:Parsed-Byin 3.x andX-Parsed-Byin 1.x. Code that used the constants needed no change for them. -
The language code is
spa(ISO 639-3), where the 1.xLanguageIdentifierreturnedes. Every stored language value and every filter on it changes with the migration. -
RecursiveParserWrapperlists the attachments depth-first, children before their container, and returns the container first. The 1.x recipe would have produced one merged text with no paths. -
The fork takes a few seconds to start the first time (the run took about 9 seconds in total); share one
PipesForkParserfor the life of the application rather than one per file. -
The fork logs "No plugins" and a missing
pluginsroot at INFO and WARN. That is expected when no pipes plugins are installed next to the program and does not affect aPipesForkParserthat reads local files.
Detection with an explicit detector
The book’s detection listings call a Detector directly with the file name as a hint. In 4.1 the detector takes a
TikaInputStream and a ParseContext, and the name goes under TikaCoreProperties.RESOURCE_NAME_KEY:
import java.nio.file.Path;
import org.apache.tika.config.loader.TikaLoader;
import org.apache.tika.detect.Detector;
import org.apache.tika.io.TikaInputStream;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.metadata.TikaCoreProperties;
import org.apache.tika.mime.MediaType;
import org.apache.tika.mime.MediaTypeRegistry;
import org.apache.tika.parser.ParseContext;
public class DetectByName {
public static void main(String[] args) throws Exception {
Detector detector = TikaLoader.loadDefault().loadDetectors();
MediaTypeRegistry registry = TikaLoader.getMediaTypeRegistry();
Path file = Path.of("renamed-invoice.png");
Metadata metadata = new Metadata();
metadata.set(TikaCoreProperties.RESOURCE_NAME_KEY, file.getFileName().toString());
try (TikaInputStream tis = TikaInputStream.get(file)) {
MediaType type = detector.detect(tis, metadata, new ParseContext());
System.out.println(type + " (supertype " + registry.getSupertype(type) + ")");
}
}
}
Output (Tika 4.1.0):
application/pdf (supertype application/octet-stream)
The .png name is only a hint; the bytes win. The same program written against 1.x would use new DefaultDetector(),
Metadata.RESOURCE_NAME_KEY and a plain InputStream, none of which compiles unchanged today.
Build files for 4.x
Import the BOM so that every Tika artifact has the same version; never mix tika-core and parser modules of different
versions (CVE-2025-66516 is the reason). The coordinates were resolved for
Setup & Installation.
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-bom</artifactId>
<version>4.1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-parsers-standard-package</artifactId>
<type>pom</type> <!-- new in 4.0: a pom, not a jar -->
</dependency>
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-serialization</artifactId> <!-- TikaLoader -->
</dependency>
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-pipes-fork-parser</artifactId> <!-- PipesForkParser -->
</dependency>
</dependencies>
The same in Gradle Kotlin DSL:
dependencies {
implementation(platform("org.apache.tika:tika-bom:4.1.0"))
implementation("org.apache.tika:tika-core")
implementation("org.apache.tika:tika-parsers-standard-package@pom")
implementation("org.apache.tika:tika-serialization")
implementation("org.apache.tika:tika-pipes-fork-parser")
}
Dependencies that need attention when you migrate:
| From | To |
|---|---|
|
|
|
|
|
Removed in 4.0; CharSoup replaces it |
|
Removed; Tika Pipes |
|
The zip distribution or the |
Your own PDFBox 2.x or POI version |
PDFBox 3 and the POI version of the Tika BOM; a different major does not work |
The Gradle snippet uses the @pom classifier that the 4.0.0 notable-changes page names for the standard package; it was
not built with Gradle for this page.
Configuration, metadata and services in one view
The three changes that break most 3.x deployments, each with its migration tool and the page that has the detail.
| Change | 3.x | 4.x | Migration aid |
|---|---|---|---|
Configuration |
|
|
|
Metadata keys |
|
|
|
Server |
|
|
Startup fails on unknown keys, which lists them. Tika Server (REST API) |
A consumer that cannot move to the new key names at once can keep reading 3.x names while the producer runs 4.x:
{
"parse-context": {
"legacy-key-migration-filter": {}
}
}
The filter rewrites keys at the emit edge (V4_TO_V3 by default). Treat it as a bridge for a migration window, not as a
permanent setting: new 4.x keys have no 3.x name, and some 3.x keys were dropped rather than renamed.
Migration checklist: 3.x to 4.1
The order matters: each step makes the next one easier to test.
-
Upgrade to 3.3.2 first and record a baseline for a corpus of your own files: detected type, text length, the metadata keys you use, the parse status. 3.3.2 already has the SAX OOXML parsers and the CVE fixes, so a later difference is a 4.x change, not a 3.x bug fix. tika-eval & Extraction Quality compares two extraction runs systematically.
-
Move every host and container to Java 17 or later.
-
Change the build: BOM 4.1.0,
tika-parsers-standard-packageaspom, addtika-serializationand, for isolation,tika-pipes-fork-parser. Removetika-batch,tika-langdetect-tikaand any separately pinned PDFBox 2. -
Fix the compile errors: wrap streams in
TikaInputStream, addParseContextto detectors and extractors, replaceTikaConfigwithTikaLoader, replace inheritedMetadataconstants (HttpHeaders.CONTENT_TYPE), replaceForkParser. Custom parsers implementParser, notAbstractParser. -
Check the code that compiles but behaves differently: streams are no longer rewound by
Tika.detect, nothing spools unless asked,TikaTimeoutExceptionis checked, and string writes totk:keys throw. -
Migrate the configuration to
tika-config.json: convertparsers, rewrite the rest, put limits inparse-context, move OCR toenginesandtext-recognizers, reference secrets as${env:NAME}. Load it once at startup so that a bad key fails the deployment, not the first request. -
Migrate metadata consumers: search code, index schemas and dashboards for
X-TIKA:and the other old prefixes; rename, or enablelegacy-key-migration-filterwhile they catch up. Re-index if the index stores the key names. -
Decide the output format: adopt Markdown (good for chunkers and models, see RAG & LLM Ingestion) or request XHTML explicitly everywhere.
-
Migrate the services: server config to JSON with
allowPipes/allowPerRequestConfig, clients to explicit handler paths and to handling429and503,numClientsand fork heap sized deliberately (see Performance & Scaling), and the timeout set on purpose (the default grew from 5 minutes to 1 hour). -
Deploy from the zip distributions or pinned images, never a bare jar or a
SNAPSHOTtag. -
Compare with the 3.3.2 baseline and explain every difference before switching traffic; the integration tests of Testing Tika Integrations are the place to keep that corpus.
For a Spring Boot application the code changes are the same; the wiring is shown on Spring Boot Integration.
Source: Apache Tika 4.1.x, Migration to 4.x and the guides it links (migrating to 4.x, migrating tika-server, metadata changes).
Upgrading from 1.x or 2.x
-
Go straight to 4.1. Both lines are end of life and affected by the 2025 XXE CVEs; an intermediate stop on 3.x only adds a second migration.
-
From 1.x, apply the 2.0 changes first in your head, then the 4.x ones: the artifact split, the metadata key clean-up (
Authortodc:creator), the removal ofLanguageIdentifier, and then everything in the 3.x checklist above. The idiom table covers the book-era code. -
From 2.x, the Java jump is from 8 to 17, the
javaxtojakartachange affects anything that shares a servlet or JAX-RS container with Tika, PDFBox goes from 2 to 3 and HTML parsing from TagSoup to JSoup, so the HTML text and structure you indexed can change. Then apply the 3.x checklist. -
Expect output differences on every format: three major versions of parser fixes, a new HTML parser, SAX OOXML parsing, a new charset pipeline and a new language detector. Measure them with a corpus; do not assume equality.
Pitfalls
-
Mixing generations of examples. A 3.x answer with
TikaConfigorX-TIKA:keys does not apply to 4.x; check the version of every snippet you copy, including the official 3.3.2examples.html, which still shows the 1.xLanguageIdentifier. -
Trusting a green build. The worst 4.x changes compile: silently ignored server headers, the 1-hour default timeout, Markdown instead of XHTML,
tk:keys that an index schema does not know. -
Upgrading one module. Different versions of
tika-coreand the parser modules are unsupported and were the root of CVE-2025-66516. -
Running a preview in production.
4.0.0-alpha-1has two CVEs;SNAPSHOTimages change every night. -
Reading the stale roadmap table as current. It predates 4.0.0; check the wiki and the news page too.
-
Forgetting the 4.2 default change. Pin the unpack format if you rely on the current one.
What was verified and what was not
Verified on 2026-10-13:
-
Release versions and dates on the Apache Tika news page, Maven Central
tika-coremetadata, the Apache download area, Docker Hub tags and the GitHub tag list; the absence of a 4.2 release. -
Both roadmap pages, quoted above, and the 1.x and 2.x end-of-life notices on the news page.
-
CVE-2025-54988, CVE-2025-66516, CVE-2026-66755 and CVE-2026-66756 in the CVE records (through the CVE Services API that backs
cve.org): publication dates, affected packages and ranges, fixed versions and CVSS scores. -
The 4.0.0 and 4.1.0 notable-changes pages, the 4.1.x migration guide headings and the 3.0.0 change log entries cited.
-
The
MigratedIntakeandDetectByNameprograms, compiled and run on Tika 4.1.0 and Java 21 with the outputs shown; thatMetadata.CONTENT_TYPEfails to compile; thatTikaConfig,ForkParser,LanguageIdentifierandMSOfficeare absent from the 4.1.0 class path, andMimeTypes,DefaultDetector,ParsingReader,LinkContentHandler,TeeContentHandler,ToMarkdownContentHandler,AutoDetectReader,LanguageHandler,TikaComponentandLegacyKeyMigrationFilterpresent.
Not verified:
-
The 1.x and 3.x listings on this page were not compiled or run; they are labelled as such.
-
The listing numbers of Tika in Action were not re-checked against the book; the table cites chapters only.
-
The 2.0 change list rests on the official wiki migration page, not on a 1.x to 2.x run.
-
The jakarta namespace of 3.x rests on the version table of the roadmap page.
-
The Gradle
@pomdependency was not built. -
The Lucene
TextFieldreplacement is the current Lucene field API in general; the Lucene version is covered on the search-indexing page.
References
-
CVE-2025-54988, CVE-2025-66516, CVE-2026-66755 and CVE-2026-66756
-
Chris A. Mattmann and Jukka L. Zitting, Tika in Action (Manning, 2011), chapters 1 to 15, written for Tika 1.0