For the complete documentation index, see llms.txt. This page is also available as Markdown.

Release v6.33.0 (2026-06-04)

Published 2026-06-04 14:28:57Z

Important

  • Data Model: Due to a wrong internal search.facet setting, masks will be cleaned up automatically when opening the data model. You will see a prompt where you need to click Ok. No other actions needed.

  • This release forces a blocking re-index. Make sure to plan enough time for this update, as your users will not be able to access the database while the re-index is running. Only /inspect/ is available while the re-index runs. The re-index clears stray date_range aggregation markers from existing objects (see /api/search under Fixed), and repairs base-type objects (messages, collections, pools, groups) whose long localized free text previously failed to index and dropped out of search (see Indexer under Fixed). [609ada17e]

  • Custom produce config: if your instance uses a custom produce config, re-check INDD handling after the update. INDD files are now produced in the office class instead of image; the migration moves indd accordingly, but INDD only produces versions where your office class has pdf versions to ride on. With no office class, or no pdf version, INDD files upload but produce nothing (no thumbnail, preview or pages). Independently of the produce config, INDD files that were already uploaded keep their old single image until you re-produce them — see /eas, produce config under Improved for how to do that from /inspect/files. [56cfeb641]

  • OAuth login redirects: a cross-origin destination reached after OAuth login must now be allow-listed via fylr.services.webapp.loginAllowRedirects, or the redirect is refused. Same-origin destinations (a local path, or one matching fylr.externalURL) keep working without configuration. The default config bakes in https://*.web.fylr.dev, http://localhost:* and https://localhost:*; if your frontend finishes login on another host, add it to the list. See OAuth login under Fixed. [545536f31]

Server

New

  • /inspect: New SQL Query utility under /inspect/sqlquery/ that lets an inspect-authenticated user run read-only SELECT queries against the configured database, with paging, ordering and a per-browser query history. The endpoint also accepts application/json, so it can be driven from apitests. Because queries run with the privileges of the configured fylr database user, it is gated behind a new config flag fylr.debug.inspectEnableSqlQuery (off by default). Enable it only on developer / debug instances, and make sure the fylr DB user is not a Postgres superuser. [96ceacb61]

  • /api/search: daterange values and date_range aggregation bucket boundaries can now carry an explicit timezone offset on partial-date precisions (year, year-month, date) — e.g. 2025+01:00, 2025-12+01:00, 2025-12-31+01:00. ISO 8601 itself does not allow timezone designators on partial dates; this is a fylr-specific extension. Untagged values continue to be interpreted as UTC, so existing data and the webfrontend are unaffected. Also removes the long-dead format parameter from date_range aggregation requests — it has been silently ignored since 2022, and unknown keys are ignored, so clients that still send it are unaffected. [eb3c57460]

  • /inspect/objects: The per-objecttype list at /inspect/objects/<table>/ now answers Accept: application/json with pagination meta and the system_object_ids on the page, so monitoring can alert on objects stuck in "not found READ" without scraping the inspect HTML. The single-object view at /inspect/objects/<id>/ gains ?datamodel=<id> to render an object against any datamodel version (current, historic or uncommitted HEAD) and ?latest_linked=0|1 to choose whether linked objects load at their stored version or the current latest. [3c5600aaa] [003a585cb]

  • OAuth2 / /api/oauth2/token: The client-credentials grant now logs in as an anonymous user. A request with grant_type=client_credentials resolves (or creates) the anonymous user bound to the browser client and returns an access token for it, so a public frontend can obtain an anonymous session without any user credentials. This requires guest access to be enabled in the base config (login.guest); with guest access off the request is rejected and a warning is written to the fylr log. Anonymous token logins are recorded as USER_LOGIN / USER_LOGIN_FAILED events. The implicit grant flow is no longer supported: /api/oauth2/auth now accepts only response_type=code (so response_type=token is rejected), and the token endpoint accepts only the authorization_code, password, client_credentials and refresh_token grant types. [cb9831058]

Improved

  • Saving objects in large instances: A save no longer leaves a record "processing" for minutes before it becomes searchable. Previously every term the object references was re-counted on every save; on large databases (millions of object↔term links) recomputing those counts dominated indexing, especially for common terms. A save now re-indexes only the terms whose link to the object actually changed — terms whose link is unchanged keep their count and are skipped — and each term's object count is read from an index-only scan instead of fetching every matching row. Deletes and undeletes still re-index the affected object's terms in full, so trashed objects keep dropping out of /api/suggest. The upgrade rebuilds an index on the object_term table, which briefly locks it during the (already re-indexing) update. [a49ab9728]

  • /api/tags: POST /tags now follows a two-step protocol when tags omitted from the request payload would be deleted. If a deleted tag is still referenced in a place that can be cleaned up automatically (collection.create_object, objecttype_tag, pool_tag), the call returns 202 with a tasks[] envelope that describes what would be removed and carries a delete_policy=remove_tags confirmation button; resend the identical request with that query parameter to confirm. If a deleted tag is referenced in a place that cannot be cleaned up automatically — object tags, the ACL of a right preset / pool / tag / objecttype, an objecttype column- or mask-filter, a workflow transition tag filter, or a path in the baseconfig — the call returns 400 with code: TagsInUse and a parameters.usages[] array listing each tag_id, context and the affected ids (or refs for baseconfig paths) so the caller can resolve each reference and retry. [49a8222e9]

  • /api/export (CSV / XLSX / XML): File-field columns now include the iiif_url and deep_link_url of each exported version alongside the existing url. CSV/XLSX produce <field>[N].iiif_url and <field>[N].deep_link_url; XML adds <iiif_url> and <deep_link_url> tags inside each <version>. iiif_url is populated for image versions whose recipe is IIIF-eligible (png/jpg/jp2/jpeg/webp up to 32000×32000 pixels), deep_link_url whenever the object UUID is known. Empty values are skipped, so columns appear only when there is a URL to emit. The same fields have always been available in JSON exports — this brings the sheet/XML formats in line. [dff5e821d]

  • /api/export[merge]: Stop wiping unmapped tags during exiftool merge exports. Previously a mapping field with xml_export paths but no easydb source emitted an empty value to exiftool, which clears that tag in the file — so a merge mapping that only configured a subset of fields ended up removing every other tag (e.g. CopyrightNotice was lost). The new behavior is opt-in via an exiftool_export_omit_empty flag on the mapping (and on the profile), set to true in export_merge.yml and empty_export_merge.yml. Existing mappings keep their previous behavior unless their profile matches one of the merge profiles, in which case the migration enables the flag for them. Fields that have an explicit easydb source still emit empty values, so an intentional clear is still possible. [97e110670]

  • /api/export & transport (ZIP): ZIP archives delivered by an export download or written by a transport (including the (s)FTP transport) are now Deflate-compressed instead of stored uncompressed, so the resulting .zip is smaller. The packaged files themselves are unchanged. [7b57c3280]

  • /eas, produce config: InDesign (INDD) files are now produced as multi-page documents instead of single raw images — reclassified from the image to the office class so pdf2pages renders one image per page from the embedded XMP previews. An upgrade migration moves indd accordingly in non-default produce configs (see Important). A recipe/extension mismatch no longer fails the whole produce config compile at startup; the offending extension is dropped with a warning. Existing INDD files keep the single image they were produced with before the update; to give them the page previews, re-produce them from /inspect/files: filter by the indd extension and run the Produce versions (produce_versions) action, which discards the old versions and re-runs each original through the new office-class pipeline. An INDD's pages are its embedded XMP previews, taken from whichever tag carries them — the multi-page PageImage set, or a single ThumbnailImage written by older InDesign versions. A file with any embedded preview produces the page/preview versions (the count is reported in technical_metadata.pages); only an INDD with no embedded preview at all produces no page/preview versions, instead of a single blank image. [56cfeb641] [2ee968d10] [55f936b68]

  • /inspect/migration: Backup and restore now reconcile deleted objects and the links pointing at them. By default the restore drops link wrappers whose target is soft-deleted, or was purged but still survives only in a historic version — in either case the link can never resolve, so a backup-then-restore no longer leaves the linking object with a "(Purged / Deferred object)" ghost in every version. Two opt-in flags preserve the round-trip: fylr backup --include-deleted includes soft-deleted objects in the payload (exposed as "Include soft-deleted objects" on the Backup form), and fylr restore --include-deleted-linked keeps the link wrappers instead of stripping them (exposed as "Include links to deleted or purged objects" on the Restore form, covering both soft-deleted and purged targets). Used together, the deleted target is restored as such and its incoming links resolve to it; used alone on the restore, the links surface as _purged_or_deferred on read. See --include-deleted and --include-deleted-linked. [894e9564e] [4266cfd8f]

  • /inspect/migration: Pools and objecttypes now carry their tag bindings — both the global tag list and any private tags scoped to that pool / objecttype — through the backup payload, so a backup-restore round-trip preserves the per-pool / per-objecttype private tags it previously dropped. [ae814db5f]

  • /inspect/migration: Restore now accepts a rename-versions parameter that renames file versions (renditions) as objects are uploaded into the target instance — useful when the source uses different version names than the target (e.g. video.1920p1080p). An empty target removes the version. The Restore form exposes a File class / Source version / Target version table that grows a row as the last one is filled, pre-populated from the previously stored restore parameters when a backup is selected. See renaming renditions during migration for the value grammar. [519b18a38]

  • Rights / saving ACLs: A user who holds only BAG_ACL (not BAG_WRITE) on a collection or pool can now change its _acl / _private_acl without also holding BAG_WRITE. BAG_WRITE is still required when the request body changes the object itself (e.g. its displayname) or _owner, and an empty body still requires BAG_WRITE. [7ca6bb518]

  • Rights / permission errors: When a save or file exchange is refused because the user is missing a right's sub-permission rather than the right itself, the error now names that sub-permission in bracket notation instead of blaming the whole right. A user who may upload files but lacks the "update and remove allowed" option of "Upload File" is now told they are missing asset_upload[allow_update_and_remove] ("Upload File[Update and remove allowed]") rather than asset_upload ("Upload File"). The bracket notation matches the form already used for system rights. [b303d565c]

  • Base config: Dependent fields in the base config editor are now hidden while the flag that enables them is off — register.form, the deep_link_access and oai_pmh fields below their enabled switch, webdav.hotfolder_wait_sec, the janitor fields below active, and loca.google_csv. This declutters the form via show_script. [e4132041e]

  • Plugins: Plugin callbacks now receive every system config parameter marked unauthenticated_visible (e.g. appearance, name), not just languages as before. A new parameter-level unauthenticated_visible flag lets you keep individual parameters out of the config handed to plugins. [c5460e665]

  • Cookies: The Secure flag on cookies set by fylr is now derived automatically from fylr.externalURL instead of being forced on for every cookie — an https:// external URL gets Secure cookies, an http:// one does not. This drops the 6.32 fylr.debug.cookieAllowInsecure escape hatch (now removed; configs that still set it are ignored) and lets /inspect/ login work on HTTP-only installs without extra configuration, which 6.32 had broken. Behind a TLS-terminating reverse proxy the cookies stay Secure as long as externalURL is the https:// URL the browser uses. [5458bf5e5]

  • /inspect/migration: Restore now accepts a rename-versions parameter that renames file versions (renditions) as objects are uploaded into the target instance — useful when the source uses different version names than the target (e.g. video.1920p1080p). An empty target removes the version. The Restore form exposes a File class / Source version / Target version table that grows a row as the last one is filled, and is pre-populated from the previously stored restore parameters when a backup is selected. See renaming renditions during migration for the value grammar. [78620]

  • API documentation: a comprehensive audit and correction of the OpenAPI documentation (/inspect/apidocs/) against the server code. Every endpoint now opens with a description and a brief per-method introduction, documents all URL parameters, the full request body and complete response coverage (the success case and every error code), and spells out each enum value. The OAuth2 / OpenID Connect endpoints (/api/oauth2/*) and the discovery document (/.well-known/openid-configuration) are now documented, and endpoints carry short "Differs from easydb 5" notes where fylr behaves differently. The same reference is now also published on GitBook at docs.fylr.io, and /inspect/apidocs/ offers a GitBook-flavoured OpenAPI 3.0 spec download (datamodel stripped) next to the full OpenAPI 3.1 JSON. [66605]

  • LDAP / SAML user mapping: The SSO login user-mapping can now target the user's address fields — country, state, postal_code, town, street, house_number and address_supplement — in addition to the existing reference, login, displayname, email, company, department, first_name, last_name and phone. Map an IdP attribute to one of these keys in the LDAP or SAML User mapping table and the value is written to the matching field on the user at login; previously these keys were silently dropped. [8c1f31fa3]

Fixed

  • /api/search: a type: "geo_shape" query that omits its geo_shape object or field reported an error naming a non-existent geo_polygon key; the message now names the real geo_shape key. [66605]

  • bgtask metadata mapping: Two bugs that surfaced together via the ai-metadata plugin. (1) A new object version produced by an overwrite_values run was attributed to the previous version's author, so a task run by user B showed up in the change history as a change by user A — the version is now attributed to the user of the saving session. (2) When a mapping field targeted a custom-data-type sub-field (e.g. weblink.text_plain) and the recipe returned an empty string, overwrite mode replaced the whole CDT and silently cleared its other sub-fields (e.g. weblink.url); empty recipe results are now skipped. [b4480b92d]

  • /api/search: Stop date_range aggregations from reporting a phantom hit on the day after a date / datetime / daterange value. The indexer used to write an extra marker at the exclusive end of a value's range (the 23:59:59Z second), which slipped into the next calendar day when an aggregation bucket carried a non-UTC offset — a 1977-05-29 value would then match a 1977-05-30 day bucket queried in +01:00. The forced re-index (see Important) clears the stray markers from existing objects. [609ada17e]

  • /api/search: Map clustering (geohash_grid) now reports a stable geo_center. It used to be the centre of the geohash cell, which changes at every zoom level, so a fixed cluster of objects appeared to jump or duplicate as the user zoomed in on the map. geo_center is now the actual centroid of the objects in the bucket and stays put across precision levels. [2004bbc32]

  • OAuth login: Reworked handling of the redirect destination carried in the OAuth state parameter at the webapp callback. Same-origin destinations — a local path, or one matching fylr.externalURL — are accepted by default; cross-origin destinations must now be allow-listed via the new fylr.services.webapp.loginAllowRedirects setting, which matches host names with RFC 6125 wildcard rules (a single * is allowed only as the entire leftmost host label) and accepts a port wildcard — :* in place of the port matches any port (including none) on the same host, so http://localhost:* allows a frontend dev server regardless of which port it picked. The default config bakes https://*.web.fylr.dev, http://localhost:* and https://localhost:* into the allow-list; customer configs replace the list unless they use loginAllowRedirects+: to extend it or loginAllowRedirects-: to drop a baked-in entry. See also Important. [545536f31] [c395ff438] [7d8a69429]

  • /api/eas/rput: Validate the URL passed to rput against a configurable host blocklist before opening the outbound connection. The new fylr.eas.rput.blockedHosts setting accepts IP/CIDR, exact-hostname and single-label-wildcard entries (each optionally pinned to a port). The compiled-in default blocks loopback, link-local and private (RFC1918 / ULA) ranges (127.0.0.0/8, ::1/128, 169.254.0.0/16, fe80::/10, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, fc00::/7). fylr's own internal services are added automatically on their exact host:port. Host names from the URL are resolved and the connection is pinned to the resolved address. The API listener stays reachable so the existing tile-restore workflow (rput on a /api/v1/eas/zoom/... URL) keeps working. [e7fdafbab] [69552956b]

  • /api/eas: iiif_url and zoom_url (signed URLs, and those carrying an obj_uuid) were broken when a version name contained a /; the version name is now escaped properly. [327e22cc2]

  • Datamodel / expert search: The auto-generated all-fields ("expert search") mask no longer defaults search.facet=true on every column — only on the column types the webfrontend renders a facet toggle for (boolean, date, datetime, daterange, link). This stops the facet flag from riding along silently on text/file columns. Only newly created masks pick up the corrected default; existing masks keep their stored facet flags. [a179d2337] [ed735999d]

  • /api/v1/user and /api/v1/group: Responses include the _acl field only for callers that hold system.user/system.root (for /user) or system.group/system.root (for /group). Applies to GET, list, POST and DELETE on both endpoints. /api/search results for type=user and type=group no longer include _acl; fetch the object via the endpoint above as an administrator to read its ACL. [68a06c30b]

  • Plugin loader: Plugin paths are now treated as literal directories; the long-broken glob support was dropped. A missing path is logged as an error and skipped, so misconfigurations stay visible. [37cc4628b] [fecad83b1]

  • Base config: Fixed loading of the client block time from the base config. [451fcc939]

  • /api/db: Fixed an occasional deadlock between the indexer and a concurrent purge that could fail DELETE /db/<table>?delete_policy=purge with a serialization error under parallel load. [86a536369]

  • Logout: Fixed a nil-pointer crash during logout. [a1781941b]

  • Pool / objecttype captions & watermarks: Changing a pool's or objecttype's caption or watermark configuration and confirming the resync could leave some file renditions rendered with the previous configuration. The cache id that tells file-produce workers to reload base data was bumped just after the change had committed instead of together with it, so a worker could start the queued resync, read the new configuration, and still re-render against the stale cache. The bump now commits atomically with the change, so every reader observes the new configuration. This affects all cached base data — pools, objecttypes, masks, datamodel, collections, transitions, tags, ACL groups and plugins — not only captions. [02c1239c8]

  • Indexer: Rejected index jobs for base types (collections, pools, groups, users, messages, terms) are now re-queued and retried, the same as object jobs. Previously, when the search cluster rejected jobs under load (rejected_execution_exception), only objects were re-queued; a base type rejected this way stayed unindexed — e.g. a newly created group or pool remained found:false. The base-type index-error event also no longer records an empty type. [f6386a9cd]

  • Indexer: Long localized free text on a base type (a message body, a collection or pool description, a group display name) no longer breaks indexing. The value was indexed as a single keyword term, and once it passed Lucene's 32766-byte limit the search cluster rejected the whole document ("immense term") — the object dropped out of the index and vanished from the frontend, and a re-index could not recover it. The text is now chunked like object text fields already are; this release's re-index repairs existing affected objects. [5216dcc85]

  • Docker image (TIFF clipping paths): The bundled ImageMagick is pinned to the last good upstream patchlevel, 7.1.2-21 (from a Debian snapshot). ImageMagick 7.1.2-23 broke rendering of embedded TIFF clipping paths — the clip step that cuts the background produced a blank, fully transparent preview, so every clipped rendition (small, preview, huge, zoom, full) came out empty. The pin is a temporary workaround and will be removed once a fixed ImageMagick reaches Debian. [b74edd8ef]

Frontend

New

  • Metadata Mapping – omit empty fields on Exiftool export : Added a new "Omit empty fields from Exiftool export" checkbox in the general tab of the mapping editor. It only appears for fylr mappings whose profile has Exiftool export enabled, and lets users opt in to skipping fields without an easydb source instead of clearing the tag in the file. (467a7ad1c)

  • Search by multiple object IDs : Search now supports filtering by several system object IDs from a single URL parameter (?sids=1,2,3), generating one combined query element instead of one per ID. This makes shared search URLs shorter and easier to build when targeting many objects at once. (d718b8b24)

  • Nested Table Popover events : Added two new events fired when a nested popover is opened and closed, giving plugins and other logic a hook to be notified of these events. (cb0891100)

  • Base Config – show_script in table fields : Added support for show_script in table field types. Fields in table rows can now be hidden based on the evaluation of a show_script expression. (a01dda7e3)

Improved

  • Task Manager – improved task editor : Improved the task editor and removed the beta limitations. (42d3f19ff)

  • Task Manager – layout tweaks : Swapped the Module/Title order and reverted sections to headlines. (9db7730fe)

  • Editor – incompatible tags on pool change : When changing the pool, incompatible tags are now removed and the user is warned before saving. (0272cddee)

  • Secure token handling on uploads : The authentication token is no longer sent as a URL parameter in PUT/POST requests for EAS uploads; it is now passed in the request headers. (8d9aa47c6)

  • Browser context menu on text and inputs : The context-menu override on right click is now disabled when the target is selected text or inside an input, so the native browser menu (copy/paste, etc.) works as expected when handling text. (787728a6b)

  • Search – "remove all" button in ez5 : Enabled the "remove all" button in the search for ez5. (96719c1c4)

  • CUI.xhr – custom request headers : Added support in CUI.xhr for adding custom headers to a request. (CUI, 0d889151)

  • Tag Manager – grouped "tags in use" errors : The TagsInUse error usages are now rendered grouped by tag with clickable links, making it easier to find where a tag is still in use. (3022aa517)

  • Customize templates – localizable preview column : The preview column in customize templates is now localizable. (8e01b4e6f)

  • Customize templates – localizable tab titles : The tab titles in customize templates are now localizable. (b4238189d)

Fixed

  • Permissions – share dialog with only BAG_ACL : Users with only BAG_ACL (and no BAG_WRITE) can now open the share dialog of a collection or pool and save their permission changes; only the ACL fields are sent so the backend accepts the save instead of rejecting it. (6b8911497)

  • Logout in cross-server mode : Fixed logout in cross-server mode so the request is sent to the destination backend instead of the frontend server, and the user is redirected back to the frontend once the backend completes the logout. (85f62dae4)

  • Export inspect icon : Fixed a bug that hid the inspect icon for exports when not in the main search view. (a699881e1)

  • Connector availability check : Fixed an error when checking connector availability for the new version of the connector plugin. (964edeb81)

  • Print Manager : Fixed harmless warnings from print assertions, stopped the frontend from trying to render tooltips in print scenarios on some browsers like Firefox, and turned a cUI.dom.empty error into a log warning instead of throwing. (1463feb7a)

  • Cross-instance request headers : Fixed an unsafe header in cross-instance requests (such as the connector) and cleared some harmless console warnings in connector scenarios. (3dbff6667)

  • User preferences for LDAP/SSO users : Fixed the visibility of the user webfrontend preferences tab in the user manager so it is shown for LDAP and SSO users. (84c34883b)

  • Hierarchy "not found" label : Fixed the "not found" label in search for hierarchy mode set to auto, which was wrongly using the top-level "not found" variant. (5cae2e42c)

  • CSV importer race condition : Fixed a race condition when building the CSV importer configurator panel, which could render before the proper dbinfo data was available and throw an error. (47b32f9bd)

  • Filter pool label for remote pools : Fixed the filter pool label for remote pools. (ff89256d9)

  • Console error when no user is selected : Fixed a console error that occurred when no user was selected. (de6f0dc94)

  • Ctrl+S in editor : Fixed the Ctrl+S shortcut in the editor. (5058948ce)

  • NoMasksForCreate API error : Fixed the NoMasksForCreate API error that occurred on a rare edge case after login. (e5f9d669f)

  • CUI.DOM.empty – less destructive assertion : Made the CUI.DOM.empty assertion less destructive: it now logs a warning instead of throwing an error that could break frontend logic. (CUI, ade1eedb)

  • Parent Column link in "Short" rendering : Fixed the link to the parent object in the parent field when the object is rendered as "Short"; the generated search was incorrect. (ecb892abe)

  • Base Config – guard for fields without a name : Added a guard so Base Config no longer dies when the server sends a field without a name in the base config file worker definition (which can happen, for example, when a buggy plugin tries to add configuration). (80314380a)

  • Datamodel – clean up stray facet flag : The Datamodel manager now detects and cleans up an old internal search.facet setting that some masks were still carrying on fields where it shouldn't be. When opening the manager, the user is prompted to re-save the masks so the leftover flag is removed and hidden fields stop showing up in expert search. (344f68c2c)

  • Task Manager – output-only details form : The form that contains the task details is now rendered as "output-only", applying a slightly lesser margin. (c9f329773)

  • Fields – navigation toolbar visibility : Made sure the navigation toolbar is actually visible so its margin is applied. (c87f782a6)

Last updated