Troubleshooting#
Common issues and their solutions when using folio-data-import.
Authentication Issues#
Error: “Invalid credentials”#
Problem: Username or password is incorrect.
Solution:
Test credentials manually:
curl -X POST https://folio-snapshot-okapi.dev.folio.org/authn/login \
-H "Content-Type: application/json" \
-H "X-Okapi-Tenant: diku" \
-d '{"username":"diku_admin","password":"admin"}'
Verify:
Username and password are correct
User has sufficient permissions
User account is active in FOLIO
Error: “Invalid tenant ID”#
Problem: Tenant ID doesn’t match FOLIO system.
Solution:
Check your tenant ID with your FOLIO administrator. Common patterns:
diku(FOLIO snapshot/demo)fs09000000(bugfest environments)Custom identifier for your institution
Error: “Connection refused” or timeout#
Problem: Cannot connect to FOLIO API.
Solution:
Test connectivity:
# Test basic connectivity
curl https://folio-snapshot-okapi.dev.folio.org/_/version
# Check if you need VPN access
# Check if the URL is correct (no trailing slash)
Verify:
FOLIO server is running
You have network/VPN access if required
Gateway URL is correct
Port is accessible (usually 443 for HTTPS)
MARC Import Issues#
Error: “Not a valid MARC file”#
Problem: File is not a valid MARC21 binary file.
Solution:
Check the file type:
file your_file.mrc
# Should show: "data" for binary MARC
# If it shows "ASCII text", it might be MARC XML
Convert MARC XML to binary if needed:
yaz-marcdump -i marcxml -o marc input.xml > output.mrc
Error: “Profile not found”#
Problem: Data Import Job Profile name doesn’t exist.
Solution:
Run without
--import-profile-nameto see available profiles interactivelyCheck exact spelling in Settings > Data Import > Job Profiles
Profile names are case-sensitive
# Let the tool show available profiles
folio-data-import marc --marc-file-path records.mrc
Job Summary Not Available#
Problem: Import completes but summary cannot be retrieved.
Solution:
Check Data Import > View all logs in FOLIO UI
Look up your job ID from
marc_import_job_ids.txtorfolio_data_import_TIMESTAMP.logUse flags to handle unreliable summaries:
# Continue without failing on missing summary
folio-data-import marc \
--marc-file-path records.mrc \
--let-summary-fail
# Skip summary retrieval entirely
folio-data-import marc \
--marc-file-path records.mrc \
--no-summary
Invalid MARC Records#
Problem: Some records fail to parse.
Solution:
Records that fail to parse are written to bad_marc_records_TIMESTAMP.mrc. Common issues:
Incorrect directory entries
Encoding issues
# Fix common leader issues
folio-data-import marc \
--marc-file-path records.mrc \
--preprocessor "fix_bib_leader,clean_empty_fields"
Batch Timeouts#
Problem: Batches timeout on slow networks or large records.
Solution:
Reduce batch size and add delay:
folio-data-import marc \
--marc-file-path records.mrc \
--batch-size 5 \
--batch-delay 2.0
Analyzing Failed Records with DI Log Retriever#
Problem: MARC import completed but many records failed. You need to see the errors and get the original MARC records.
Solution:
Use the get-di-logs command to retrieve error logs directly from the database:
# Retrieve errors from previous import jobs
folio-data-import get-di-logs \
--db-config db_config.json \
--job-ids-file marc_import_job_ids.txt \
--report-file-path errors.tsv \
--marc-file-path failed_records.mrc
This generates:
errors.tsv- Error messages for each failed recordfailed_records.mrc- MARC file with all failed records for reprocessing
See the DI Log Retriever Guide for complete documentation.
DI Log Retriever Issues#
Error: “PostgreSQL support requires the ‘postgres’ optional dependencies”#
Problem: The psycopg2 library is not installed.
Solution:
Install the PostgreSQL dependencies:
pip install 'folio_data_import[postgres]'
# or
uv add 'folio_data_import[postgres]'
Error: “Connection refused” or database timeout#
Problem: Cannot connect to the PostgreSQL database.
Solution:
Verify database host and port in
db_config.jsonCheck if you need SSH tunneling (most production databases do)
Verify firewall rules allow your connection
Test database connectivity:
psql -h your-host -p 5432 -U folio -d folio
Error: “ssh_host is required when ssh_tunnel is enabled”#
Problem: SSH tunnel is enabled but the bastion host is not specified.
Solution:
Add the ssh_host to your ssh_config.json:
{
"ssh_tunnel": true,
"ssh_host": "bastion.example.com",
"use_ssh_config": true
}
No Error Records Found#
Problem: Command runs but returns no errors.
Solution:
Verify the Job Execution IDs are correct (copy from FOLIO Data Import logs)
Confirm the jobs actually had errors (not just warnings)
Check you’re connecting to the correct database and tenant
Verify the database user has SELECT permissions on:
{tenant}_mod_source_record_manager.journal_records{tenant}_mod_source_record_manager.incoming_records
User Import Issues#
Error: “library_name is required”#
Problem: Missing required --library-name parameter.
Solution:
Always provide --library-name:
folio-data-import users \
--library-name "Main Library" \
--user-file-path users.jsonl
Or set via environment variable:
export FOLIO_LIBRARY_NAME="Main Library"
Error: “Patron group not found”#
Problem: Patron group name in user data doesn’t exist in FOLIO.
Solution:
Check Settings > Users > Patron Groups for exact names
Use exact case-sensitive names or UUIDs in your data
Create missing patron groups before import
Error: “Service point not found”#
Problem: Service point code doesn’t exist in FOLIO.
Solution:
Check Settings > Tenant > Service Points for codes
Use exact codes in
servicePointsUser.servicePointsIdsService points must exist before import
Duplicate User Errors#
Problem: User already exists with same username/barcode/externalSystemId.
Solution:
The importer updates existing users when a match is found. Check:
Your
--user-match-keysetting matches your data structureIf using
idfield, it always takes precedenceReview failed records in
failed_user_import_TIMESTAMP.txt
Field Protection Not Working#
Problem: Protected fields are still being updated.
Solution:
Use dot notation for nested fields:
personal.emailnot justemailCheck both CLI
--fields-to-protectand per-recordcustomFields.protectedFieldsFields must match exactly (case-sensitive)
# Correct nested field notation
folio-data-import users \
--library-name "Main Library" \
--user-file-path users.jsonl \
--fields-to-protect "username,barcode,personal.email,personal.phone"
Batch Poster Issues#
Error: “Invalid object type”#
Problem: Unrecognized --object-type value.
Solution:
Use one of the supported types (case-sensitive):
InstancesHoldingsItems
folio-data-import batch-poster \
--object-type Items \
--file-path items.jsonl
Error: “Missing required field”#
Problem: Record missing a required field.
Solution:
Required fields vary by object type:
Instances:
id,title,instanceTypeId,source
Holdings:
id,instanceId,permanentLocationId,sourceId
Items:
id,holdingsRecordId,materialTypeId,permanentLoanTypeId,status
Upsert Not Updating Records#
Problem: Existing records not being updated.
Solution:
Ensure
--upsertflag is providedRecords are matched by
id- IDs must match exactlyCheck that the ID exists in FOLIO
# Verify record exists
curl -H "X-Okapi-Token: $TOKEN" \
"https://your-folio.example.com/item-storage/items/YOUR-ITEM-ID"
Item Status Being Overwritten#
Problem: Item status changes during upsert when you want to preserve it.
Solution:
Item status is preserved by default. If status is being overwritten:
Check you’re not using
--overwrite-item-statusVerify your input data has the correct status
Preservation Options Not Working#
Problem: Statistical codes, notes, etc. not being preserved.
Solution:
Preservation options only work with --upsert:
folio-data-import batch-poster \
--object-type Items \
--file-path items.jsonl \
--upsert \
--preserve-statistical-codes \
--preserve-administrative-notes
File Format Issues#
Error: “Invalid JSON”#
Problem: JSON Lines file has syntax errors.
Solution:
Validate each line is valid JSON:
# Check for JSON errors
while read line; do echo "$line" | jq . > /dev/null || echo "Invalid: $line"; done < users.jsonl
# Or validate entire file
jq -c '.' users.jsonl > /dev/null
Error: “Unexpected character”#
Problem: File encoding issues or BOM (byte order mark).
Solution:
Remove BOM and ensure UTF-8 encoding:
# Remove BOM
sed -i '1s/^\xEF\xBB\xBF//' file.jsonl
# Convert encoding
iconv -f ISO-8859-1 -t UTF-8 old.jsonl > new.jsonl
Empty or Missing File#
Problem: File path not found or file is empty.
Solution:
Use absolute paths or correct relative paths
Verify file exists and has content
Check glob patterns expand correctly
# Test glob pattern
ls exports/*.mrc
# Use quotes around glob patterns
folio-data-import marc --marc-file-path "exports/*.mrc"
Performance Issues#
Slow Imports#
Problem: Import is running very slowly.
Solutions:
Increase batch size (within API limits):
# BatchPoster default is 100, can go up to 1000
folio-data-import batch-poster \
--object-type Instances \
--file-path instances.jsonl \
--batch-size 500
# User import default is 250
folio-data-import users \
--library-name "Main Library" \
--user-file-path users.jsonl \
--batch-size 500
Increase concurrent requests (user import):
folio-data-import users \
--library-name "Main Library" \
--user-file-path users.jsonl \
--limit-async-requests 20
Check FOLIO server performance - slow responses indicate server-side issues
Debugging#
View Detailed Logs#
All commands output logs to the console. For more detail:
# Disable progress bars to see all log output clearly
folio-data-import marc \
--marc-file-path records.mrc \
--no-progress
Check Output Files#
Review generated output files:
# MARC import job IDs
cat marc_import_job_ids.txt
# Failed MARC records
ls bad_marc_records_*.mrc
ls failed_batches_*.mrc
# Failed user imports
cat failed_user_import_*.txt
Test with Small Sample#
Test configuration with a small subset first:
# Extract first 10 records
head -10 large_file.jsonl > sample.jsonl
# Test with sample
folio-data-import batch-poster \
--object-type Items \
--file-path sample.jsonl
Validate Data Before Import#
Pre-validate your data:
# Check JSON Lines format
wc -l users.jsonl # Count records
head -1 users.jsonl | jq . # View first record structure
# Check for required fields
jq -r 'select(.patronGroup == null) | .username' users.jsonl
Getting Help#
If you can’t find a solution:
Check the full error message and logs
Review Examples for similar workflows
Check the specific guide for your import type:
Report issues on GitHub with:
Command used (sanitize credentials)
Full error message
Sample data (if possible)