None of the OAI links (for example repository.uaeh.edu.mx/revistas/index.php/serendipia/oai?verb=ListRecords&metadataPrefix=oai_dc) for my journals are currently working. When I attempt to use ListRecords, the system returns a 500 error after upgrading OJS to version 3.3.0-20. As a result, metadata cannot be harvested by services such as DialNET, BIBLAT, and others. Could you please help me? In my case, I don’t see any specific error details in the OAI link itself, so I’m not sure what might be causing this, and check the Modsecurity and nothing blocked, i tried to enable debug mode and show stracktraces in the config.inc.php, and no error related to the OAI, if any body know what’s going on please?
We are running OJS 3.3.0-20 on Ubuntu Server 24.04 with PHP 8.0.30 (Apache module, not FPM).
When accessing OAI-PMH endpoints (e.g. ...?verb=GetRecord, ...?verb=ListRecords), we consistently get HTTP 500 with an empty body.
Steps already tried:
Verified PHP logs (error.log, custom php-apache-ojs.log, etc.) — no clear fatal error, mostly deprecated notices from Smarty2 but nothing critical.
Enabled show_stacktrace and debug options in config.inc.php — pages then exposed more details, but disabling them allowed normal access again.
Checked ModSecurity:
Confirmed module active (security2_module).
Temporarily disabled globally caused Apache reload failures due to missing directives.
Tried targeted disable rules for /oai in vhost, but no improvement.
No direct ModSecurity audit logs triggered by /oai requests.
Confirmed it’s not /public restrictions: we disallow PHP in /public, but OAI-PMH runs through index.php/.../oai, not /public.
Patch attempts:
Applied recent fixes related to strip_tags() in Dc11SchemaArticleAdapter.inc.php (from newer OJS releases).
Cleaned HTML tags in dc:title and dc:description metadata before output.
After patching, Identify works, and ListIdentifiers returns IDs, but GetRecord and ListRecords still produce HTTP 500 with empty body.
Tested with curl (with/without encoding, Accept-Encoding, different HTTP versions) — consistent 500 Internal Server Error.
Apache virtual host reviewed:
SSL vhost has CORS headers open for /oai.
Rewrite rules and permissions reviewed (Require all granted).
Only ModSecurity conditional blocks active for specific IPs, but not for /oai.
Current situation
Identify works fine.
ListIdentifiers works.
GetRecord and ListRecords → always 500 (empty body).
Looks like a PHP fatal error but not logged (possibly suppressed?).
It’s hard to know where to start without an error message to go with that 500. We used to have a few places where PHP errors were suppressed, but those are long gone, even in the older OJS 3.3.0-x branch.
If I were trying to track this down, I’d start stepping through the OAI handling code to find the last executed line of code before the 500 error is triggered.
I would also be tempted to use diff or an equivalent tool to compare my installed codebase with a stock .tar.gz download of the same version of OJS.
Regards,
Alec Smecher
Public Knowledge Project Team
We used php_admin_value auto_prepend_file with a small oai_prepend.php script to capture exceptions and full stack traces into the error log.
Root Cause Identified
The stack trace showed that FilterDAO was trying to instantiate nlm30 adapters.
We confirmed in the database (filter_groups, filters, filter_settings) that there were leftover nlm30 entries, even though the nlm30 plugin was removed in OJS 3.1+.
Database Cleanup
First, inspect the database to confirm the presence of nlm30 entries:
USE DB_name;
-- Check for nlm30 filter groups
SELECT * FROM filter_groups
WHERE symbolic LIKE '%nlm30%'
OR display_name LIKE '%nlm30%'
OR description LIKE '%nlm30%';
-- Check for nlm30 filters
SELECT f.*
FROM filters f
JOIN filter_groups g ON g.filter_group_id = f.filter_group_id
WHERE g.symbolic LIKE '%nlm30%'
OR f.class_name LIKE '%Nlm30%';
-- Check for nlm30 filter settings
SELECT fs.*
FROM filter_settings fs
JOIN filters f ON f.filter_id = fs.filter_id
JOIN filter_groups g ON g.filter_group_id = f.filter_group_id
WHERE g.symbolic LIKE '%nlm30%'
OR f.class_name LIKE '%Nlm30%';
Then delete in the correct order (filter_settings → filters → filter_groups):
`START TRANSACTION;`
`– 1) Delete nlm30 filter settings`
`DELETE fs FROM filter_settings fs`
`JOIN filters f ON f.filter_id = fs.filter_id`
`JOIN filter_groups g ON g.filter_group_id = f.filter_group_id`
`WHERE g.symbolic LIKE ‘%nlm30%’ OR f.class_name LIKE ‘%Nlm30%’;`
`– 2) Delete nlm30 filters`
`DELETE f FROM filters f`
`JOIN filter_groups g ON g.filter_group_id = f.filter_group_id`
`WHERE g.symbolic LIKE ‘%nlm30%’ OR f.class_name LIKE ‘%Nlm30%’;`
`– 3) Delete nlm30 filter groups`
`DELETE FROM filter_groups`
`WHERE symbolic LIKE ‘%nlm30%’`
`OR display_name LIKE ‘%nlm30%’`
`OR description LIKE ‘%nlm30%’;`
`COMMIT;`
Glad to hear you got it going (and thanks for the details)! I’m still stumped about what was suppressing the messages, but maybe this will save someone else some time.
Thanks,
Alec Smecher
Public Knowledge Project Team
What was suppressing the error messages? in my case:
1. VirtualHost directives overriding php.ini
------------------------------------------------
In default-ssl.conf there were lines like:
php_admin_flag display_errors on
php_admin_flag log_errors on
php_admin_value error_log /var/log/apache2/ojs_php_errors.log
These php_admin_* directives always override php.ini.
Since the error_log was pointing to /var/log/apache2/... (a path where www-data had no write permission), errors were never actually written.
Also, with display_errors on for OAI, any PHP notice injected into the XML would break the OAI response.
2. Corrupted php.ini header
------------------------------------------------
The php.ini started with:
e[PHP]
instead of:
[PHP]
Because of that, Apache/PHP was complaining:
PHP: syntax error, unexpected END_OF_LINE, expecting '=' in /etc/php/8.0/apache2/php.ini on line 2
In this state, PHP ignored the intended logging configuration and silently fell back to defaults, further suppressing error output.
Resolution
------------------------------------------------
- Fixed the header in php.ini to [PHP].
- Created a dedicated log file /var/log/ojs/ojs_php_errors.log with proper ownership (www-data:adm).
- Updated VirtualHost blocks so all sections (including OAI) use:
php_admin_flag display_errors off
php_admin_flag log_errors on
php_admin_value error_log /var/log/ojs/ojs_php_errors.log
Once that was corrected, enabling a temporary auto_prepend_file for debugging allowed all exceptions/stack traces to be captured, which revealed the real cause (obsolete nlm30 filter entries in the database).