Apache Tika 4.0.0
Tika 4.0.0 is the first stable release of the 4.x line. As a new major version it includes breaking changes; the highlights are below, and the CHANGES-4.0.0.txt file carries the complete delta from 3.x, including everything first released in 4.0.0-alpha-1 and 4.0.0-beta-1.
Upgrading from 3.x? Start with the migration guides -- "Migrating to Tika 4.x", "Migrating Tika Server to 4.x" and "Metadata Changes in Tika 4.x". They carry the detail and the code examples behind the summaries here.
The 3.x line remains supported. See the download page for both.
Architecture: parsing moves out of process
- Parsing now runs in a forked process where possible. tika-server's endpoints, tika-app's -a/--async and -f/--fork, and tika-grpc all parse in forked, crash-isolated tika-pipes workers, so a parser crash, OOM or timeout no longer takes down the caller. Applications embedding Tika should consider getting the same isolation from PipesForkParser (tika-pipes-fork-parser) rather than parsing in-process with AutoDetectParser. Note that the project does not treat denial of service as a security issue when files are parsed outside these isolated paths; see the security model (TIKA-4809).
- The cost is a sizing decision 3.x never asked of you: in tika-server, numClients is both the concurrency ceiling and the CPU/memory footprint, and each fork's heap is set with pipes.forkedJvmArgs (e.g. -Xmx1g), not the server JVM's. Size both deliberately; see the CPU and heap sizing docs.
- ForkParser and the entire org.apache.tika.fork package are removed from tika-core, superseded by PipesForkParser (TIKA-4554, TIKA-4571, TIKA-4651).
Breaking Changes: platform, packaging and output
- Tika 4.x requires Java 17 or later; 3.x built and ran on Java 11 (TIKA-4685).
- tika-app and tika-server-standard now ship as zip distributions with an adjacent lib/ directory; the published jars are thin launchers and fail with NoClassDefFoundError if run on their own. This catches tika-server-standard hardest, because its jar is still on Maven Central: unzip the distribution and run from inside it (TIKA-4733).
- The default content handler is now Markdown. tika-app, tika-server (the /tika and /rmeta endpoints) and the async/pipes CLI emit Markdown content by default instead of XHTML/XML (plain text for the async CLI). Request the previous format explicitly: tika-app -x/--xml, the server's /tika/xml and /rmeta/xml paths, the async CLI --handler x (TIKA-4663).
- Configuration moved from XML to JSON. TikaConfig and the org.apache.tika.config XML-configuration API are removed; use TikaLoader from tika-serialization. tika-app --convert-config-xml-to-json converts a 3.x parsers section as a starting point; every other section needs manual migration (TIKA-4544, TIKA-4545, TIKA-4553, TIKA-4565).
- tika-parsers-standard-package is now a pom, not a jar. Users must add <type>pom</type> in Maven or @pom in Gradle (TIKA-4712).
Breaking Changes: metadata keys
- Metadata keys were renamed for consistency and provenance. Every Tika-asserted key now lives under a single tk: prefix, replacing 3.x's scattered X-TIKA:, tika:, tika_pg:, rendering:, signature: and imagereader: prefixes and bare names such as resourceName. Code using the TikaCoreProperties constants is unaffected; code that references keys by String should consult the key-for-key tables in the metadata-changes guide (TIKA-4816).
- The opt-in legacy-key-migration-filter restores 3.x key spellings at the emit edge, so an unmigrated consumer keeps working against 4.x output. tika-core bundles metadata-migration-3x-4x.json, the machine-readable rename/drop table (TIKA-4797).
- The reserved tk: namespace is now a trust boundary for String-keyed writes: Metadata#set/add(String, String) throw IllegalArgumentException on a reserved key instead of 3.x's silent success, where a document-controlled property could overwrite Tika's own value. Document- and tool-derived names go through Metadata#add(KeyPrefix, String, String) (TIKA-4816).
- Metadata no longer implements CreativeCommons, Geographic, HttpHeaders, Message, ClimateForcast, TIFF or TikaMimeKeys: inherited constants move to their home interface, e.g. Metadata.CONTENT_TYPE becomes HttpHeaders.CONTENT_TYPE (TIKA-4816).
Breaking Changes: Java API
- The core SPI signatures changed. Parser.parse takes a TikaInputStream instead of an InputStream, Detector.detect takes (TikaInputStream, Metadata, ParseContext), and EmbeddedDocumentExtractor's methods gained a ParseContext. Every third-party implementation must be updated (TIKA-4399, TIKA-4541, TIKA-4569).
- TikaInputStream no longer caches by default. A stream is consumed in passthrough mode unless enableRewind() is called at position 0; rewind()/getFile()/getPath() after reading without enableRewind() throw instead of silently spooling (TIKA-4618, TIKA-4623).
- Unified timeout model across the library, pipes and server: a total-task budget plus a progress/stall timeout, composed recursively over embedded documents. TikaTimeoutException is now a checked exception (TIKA-4813).
- Parsers and detectors no longer expose bean setters/getters for their settings; configuration moves to per-component *Config objects supplied through the ParseContext (TIKA-4758).
- The encoding detectors moved out of parser packages into org.apache.tika.detect.* and into new tika-encoding-detector-* modules (TIKA-4685, TIKA-4720).
Breaking Changes: tika-server
- Capability flags are default-deny and split in two. enableUnsecureFeatures no longer exists -- a config still carrying it fails to start -- and is replaced by allowPipes (gates /pipes and /async) and allowPerRequestConfig (gates the /config endpoints and the multipart config part) (TIKA-4764).
- Caller errors now map to accurate HTTP status codes instead of always returning 200 or 500: 429 for a saturated worker pool, 503 for a crashed/timed-out/OOM worker, 400 for an unknown fetcher/emitter or bad handler, and 413 for an over-limit body. Error bodies are JSON where 3.x returned plain text (TIKA-4809).
- Endpoints removed (/translate/*, /tika/main, the /tika/form family) and collapsed (/detect/stream is now /detect; /language/stream and /language/string are both /language). Per-request configuration headers -- writeLimit, X-Tika-Handler, the meta_* family and friends -- are removed and silently ignored if sent. The Accept header no longer selects the output format; the path names it (TIKA-4809).
- Many server config keys were removed or renamed, and an unrecognized key now fails startup with an error naming it. One change no startup error will flag: taskTimeoutMillis is now parse-context.timeout-limits.totalTaskTimeoutMillis, and its default grew from 5 minutes to 1 hour (TIKA-4809, TIKA-4813).
New Features
- New inference and OCR modules: tika-inference and tika-vlm add vision-language-model parsers (Claude, Gemini, OpenAI) for documents OCR cannot read, and tika-parser-tess4j-module adds in-process Tesseract OCR (TIKA-4665, TIKA-4666, TIKA-4667, TIKA-4690).
- tika-pipes gains three parse modes: NO_PARSE (detect only), CONTENT_ONLY (emitters write raw content, no metadata envelope) and UNPACK (write embedded bytes out), all wired through tika-app and tika-server (TIKA-4631, TIKA-4637, TIKA-4656).
- New tika-pipes plugins: Elasticsearch emitter, Atlassian JWT fetcher, Google Drive, Microsoft Graph, Azure Blob, JSON and HTTP plugins, and an Apache Ignite ConfigStore for runtime fetcher/emitter configuration (TIKA-4672, TIKA-4604, TIKA-4583, TIKA-4587, TIKA-4598).
- Unified XMP extraction across containers; adds HEIF/HEIC and WebP XMP, including Samsung/Google Motion Photo (TIKA-4775).
- A Markdown parser with structured, lossless XHTML output, complementing the Markdown content handler (TIKA-4770).
- Content-based detection of ASN.1/DER crypto containers, enabled by default: the PKCS#7/CMS, PKCS#12 and RFC 5544 timestamped-data families gained magic where 3.x had globs only. Files that detected as application/octet-stream in 3.x may now detect as a crypto type (TIKA-1997, TIKA-2856).
- tika-app and tika-server can load extra jars from the directory named by the -Dtika.extras.dir system property, without repackaging the application. Off by default; the directory is a trusted code location (TIKA-4755).
Other Changes
- Release artifacts are now channel-specific. Maven Central gets slim per-module jars; the Apache dist area gets runnable zip distributions and drop-in pf4j plugin zips; Docker Hub gets ready-to-run images (TIKA-4733).
- The charset, junk-text and language detection stack was rewritten: language-aware charset detection, a universal junk detector, wider Unicode handling and the new CharSoup language detector, which replaces the removed tika-langdetect-tika module as the bundled default (TIKA-4662, TIKA-4671, TIKA-4675, TIKA-4691).
- Pipes now carries small documents to the forked worker inside the request instead of writing them to disk first: content at or below pipes.maxInlineBytes (default 10 MB) rides in the request and touches no disk (TIKA-4808).
- Audio cover art is now extracted as embedded documents from MP3, MP4, Vorbis and FLAC, so embedded-document counts and /rmeta list lengths for audio files change (TIKA-4801).
- New audio/video metadata: audio:bitrate, audio:channels, video:frame-rate, video:bitrate and MP4 sample size, among others (TIKA-4777, TIKA-4779, TIKA-4780, TIKA-4781).
- Modules removed with no direct replacement: tika-batch, tika-dl, the advanced media module, tika-fuzzing, tika-age-recogniser, tika-server-eval, the dotnet bindings and snaps deployment. tika-app's -bc batch mode has no successor flag; use -a/--async (TIKA-4333, TIKA-4499, TIKA-4500, TIKA-4506).
- Dependency upgrades throughout the 4.0.0 line, including Jetty 11 -> 12.1.12, CXF 4.0 -> 4.2.3 and SolrJ 8.11.4 -> 10.0.0 (TIKA-4327, TIKA-4789).
Contributors
The following people have contributed to Tika 4.0.0 -- via code, patches, pull requests, bug reports, review and discussion. Thank you!
- Aashish Tudu
- Adrian Bird
- Adrien Nguyen
- Alessandro Scaldaferro
- Alexander Veit
- Chengxin Xu
- Chinh Nguyen
- Chris Mattmann
- Claude Warren
- Damien Bories
- Dave Meikle
- David Frizelle
- Davide Polato
- Dominik Schmidt
- Eric Pugh
- Eric Schoen
- Erwan Hervé
- Francesco
- Ghiles OUAREZKI
- Grant Ingersoll
- Grigorii Ioffe
- Iachimoe
- Jakub Gawlik
- james
- Junran
- Justin Deoliveira
- Klara Mazurak
- Konrad Windszus
- Kristian Rickert
- L3odr0id
- Laura Delmaestro
- Lawrence Moorehead
- Leonid Gorshenev
- Leszek Sliwko
- Lewis John McGibbney
- Lonzak
- Manish S N
- Matt Dutton
- Matthias Hofbauer
- mbiso
- Michele Andreano
- Naveed Khan
- Nicholas DiPiazza
- Nick Burch
- Nino Skopac
- Oleg Tikhonov
- Olivier Ceulemans
- Peter Hoogendijk
- Philipp Ottlinger
- Pleeplop
- Pontus Amberg
- Ray Gauss II
- Roberto Benedetti
- Ross Johnson
- Ruairidh Williamson
- Salvatore MORANA
- Sandeep Kulkarni
- Sebastian Nagel
- Shawn Rutledge
- Srinivasarao Daruna
- Srujana Kuntumalla
- Stephen H
- Steven Huypens
- Subbu
- Thomas Mortagne
- Tiancheng Dai
- Tilman Hausherr
- Tim Allison
- Tim Barrett
- Timo Boehme
- Tom Brisland
- V. S.
- Valery Yatsynovich
- Vasiliy Mikhailov
- Willy T. Koch
See https://s.apache.org/9bn57 for more details on these contributions.


