FAQ & Troubleshooting¶
This document answers frequently asked questions and provides solutions to common problems you may encounter while using odoo-data-flow.
Frequently Asked Questions¶
What is odoo-data-flow?¶
It is a powerful Python library designed to handle the import and export of data to and from Odoo. It allows you to define complex data transformations in Python, providing a robust and repeatable process for data migrations.
How is this different from Odoo’s standard import tool?¶
While Odoo’s built-in import is great for simple tasks, odoo-data-flow offers several key advantages for complex or large-scale migrations:
Separation of Concerns: It cleanly separates the data transformation logic (cleaning your source data) from the data
loading logic (importing into Odoo).
Robust Error Handling: Its
load->createfallback mechanism provides the speed of batch imports while automatically switching to single-record imports for failed batches to provide precise, row-level error messages. The smart, automatic two-pass strategy seamlessly handles complex relational data.Powerful Transformations: You can use the full power of Python and a rich set of built-in
mapperfunctions to handle almost any data transformation challenge.Repeatability and Version Control: Since your transformation logic is code, it can be version-controlled (with Git), tested, and reused across multiple environments (like staging and production) with confidence.
Can I use this for both importing and exporting?¶
Yes. The library provides tools for both workflows. The Processor and mapper modules are used for transforming and preparing data for import, while the odoo-data-flow export command is used to export data from Odoo into CSV files.
Can I migrate data directly between two Odoo databases?¶
Yes. The library includes a powerful odoo-data-flow migrate command that performs a complete export, transform, and import from one Odoo instance to another in a single step, without creating intermediate files. This is ideal for migrating data from a staging server to production.
For detailed instructions, see the Server-to-Server Migration Guide.
How do I process a CSV file that has no header?¶
The Processor can be initialized directly with in-memory data. If your source file has no header, you can read it manually using Python’s standard csv module and provide your own header list.
Read the raw data from the CSV file into a list of lists.
Create a Python list containing the header names in the correct order.
Initialize the
Processorusing theheader=anddata=arguments instead offilename=.
import csv
from odoo_data_flow.lib.transform import Processor
# 1. Define the header manually
my_header = ['LegacyID', 'FirstName', 'LastName', 'Email']
my_data = []
# 2. Read the file into a list
with open('origin/contacts_no_header.csv', 'r') as f:
reader = csv.reader(f)
my_data = list(reader)
# 3. Initialize the Processor with the in-memory data
processor = Processor(header=my_header, data=my_data)
# You can now proceed with your mapping as usual
# my_mapping = {'name': mapper.concat(' ', 'FirstName', 'LastName'), ...}
Where can I find a complete, real-world example?¶
A full example project, demonstrating a realistic data migration workflow with multiple models and complex transformations, is available on GitHub. This is an excellent resource for seeing how all the pieces fit together.
Can odoo-data-flow connect directly to Google Sheets?¶
No, the odoo-data-flow library cannot connect directly to Google Sheets to read data.
The tool is designed to read data from local files on your computer, specifically in either CSV or XML format. It does not have the built-in functionality to authenticate with Google’s services and pull data directly from a spreadsheet URL.
Recommended Workflow¶
The standard and easiest way to use your data from Google Sheets is to first download the sheet as a CSV file and then use that local file with the tool.
Open your spreadsheet in Google Sheets.
From the top menu, select File -> Download.
Choose the Comma-separated values (.csv) option.
This will save the current sheet as a
.csvfile to your computer’s “Downloads” folder.You can then use that downloaded file with the
odoo-data-flowcommand:odoo-data-flow import --file /path/to/your/downloaded-sheet.csv
This workflow ensures that you have a local copy of the data at the time of import and allows you to use all the powerful transformation features of the library on your spreadsheet data.
I can’t connect to my cloud-hosted Odoo instance (e.g., Odoo.sh). What should I do?¶
This is a common issue. When connecting to a cloud-hosted Odoo instance, you often need to use a secure connection protocol.
The solution is typically to set the protocol in your conf/connection.conf file to jsonrpcs (note the s at the end for “secure”).
While Odoo’s external API has historically used XML-RPC, modern cloud instances often require the secure JSON-RPC protocol for integrations.
Example Configuration for a Cloud Instance¶
Your conf/connection.conf should look something like this:
[Connection]
hostname = my-project.odoo.com
port = 443
database = my-project-production
login = admin
password = xxxxxxxxxx
uid = 2
protocol = jsonrpcs
Key things to check:¶
Protocol: Ensure it is set to
jsonrpcs.Port: Secure connections almost always use port
443.Hostname & Database: Make sure you are using the correct hostname and database name provided by your cloud hosting platform (e.g., from your Odoo.sh dashboard). These are often different from the simple names used for local instances.
Troubleshooting Common Errors¶
When an import fails, understanding why is key. Here are some of the most common issues and how to solve them.
Understanding the Failure Files¶
The library uses a powerful two-tier failure handling system to maximize success and provide clear feedback.
Tier 1: The load -> create Fallback (During a Normal Import)¶
When you run a normal import, the tool first tries to import each batch of records using Odoo’s fast, multi-record load method.
If
loadfails for a batch: Instead of writing the entire batch to a fail file, the importer automatically falls back to a slower, more robustcreatemethod for each record within that failed batch.This “rescues” the good records: Any records that succeed during the
createretry are imported successfully._fail.csvis created: Only the single, specific record that failed thecreatecall is written to the<model_name>_fail.csvfile. (e.g.,res_partner_fail.csv)**:When it’s created: During the first pass (a normal import).
What it contains: If a batch of records fails to import, this file will contain the entire original, unmodified batch that failed.
Purpose: This file is for automated processing. It’s the input for the second pass (
--failmode).
Tier 2: The --fail Mode¶
When you run the import again with the --fail flag, it enters a dedicated recovery mode:
It reads the highly-focused
<model_name>_fail.csvfile.It uses a safe, single-threaded, “create-only” mode to retry each record.
Any records that still fail are written to a final, timestamped
..._failed.csvfile for your manual review.
<original_filename>_YYYYMMDD_HHMMSS_failed.csv(e.g.,data_20250626_095500_failed.csv):When it’s created: During the second pass (when you run with the
--failflag).What it contains: This file contains only the individual records that still failed during the record-by-record retry. Crucially, it includes an extra
_ERROR_REASONcolumn explaining exactly why each record failed.Purpose: This file is for human review. The error messages help you find and fix the specific data problems.
Your recommended workflow should be:
Run your
load.shscript or theodoo-data-flow importcommand.If a
<model_name>_fail.csvfile is created, run the command again with the--failflag.If a timestamped
..._failed.csvfile is created, open it to identify the data issues using the_ERROR_REASONcolumn.Fix the issues in your original source file or your
transform.pyscript.Delete the
_fail.csvand_failed.csvfiles and rerun the entire process from the beginning.
Record Count Mismatch¶
Sometimes, the number of records in your source file doesn’t match the number of records created in Odoo, even if there are no errors in the final failure file.
Cause: This usually happens when your mapping logic unintentionally filters out rows. For example, using a
postprocessfunction that can return an empty value for an external ID (idfield). If the external ID is empty, the entire record is skipped without error.Solution:
Check your
idfield: The most common culprit is the mapping for theidfield. Ensure it always returns a non-empty, unique value for every row you intend to import.Use a
preprocessor: For complex debugging, you can use a preprocessor function to add a unique line number to each row. Import this line number into a custom field in Odoo (x_studio_import_line_number). After the import, you can easily compare the line numbers in your source file with those in Odoo to find exactly which rows were skipped.
Connection Errors¶
These errors usually happen when the odoo-data-flow client cannot reach your Odoo instance.
Error:
Connection refusedCause: The
hostnameorportin yourconf/connection.confis incorrect, or the Odoo server is not running.Solution: Double-check your connection details and ensure the Odoo instance is active and accessible.
Error:
Wrong login/passwordCause: The credentials in
conf/connection.confare incorrect.Solution: Verify your
database,login, andpassword.
Odoo Access & Validation Errors¶
These errors come directly from Odoo when the data is not valid enough to save.
Error:
AccessError,You are not allowed to modify this documentCause: The user specified by
uidin yourconf/connection.conflacks the necessary permissions (e.g., Create or Write access) for the target model.Solution: Check the user’s Access Rights in Odoo’s settings.
Error:
ValidationError: A required field was not providedCause: Your transformed CSV file is missing a column for a field marked as
required=Trueon the Odoo model.Solution: Check the model’s definition in Odoo and ensure your
transform.pyscript generates a value for that field.
Error:
No matching record found for external id '__export__.my_external_id_123'Cause: You are trying to link to a related record (e.g., setting the
partner_idon a sales order), but the external ID you are providing does not exist in the database.Solution:
Ensure you have successfully imported the parent records first.
Check for typos. The prefix and value used in your
m2o_mapmust exactly match the external ID of the parent record.See the section below on Import Order.
Understanding Import Order for Relational Data¶
A very common reason for the No matching record found error is that you are trying to import records in the wrong order.
The Rule: You must always import “parent” records before you import the “child” records that refer to them.
Example: Imagine you are importing Contacts (
res.partner) and assigning them to Contact Tags (res.partner.category). Odoo cannot assign a contact to the “VIP” tag if that “VIP” tag doesn’t exist in the database yet.Correct Import Sequence:
First, import
res.partner.category: Run a transformation and load process for your contact tags. This creates the tags and their external IDs in Odoo.Then, import
res.partner: Run a separate process for your contacts. The mapping for thecategory_id/idfield can now successfully usemapper.m2o_mapto look up the external IDs of the tags you created in the first step.
However, for self-referential models (like importing partners with a parent_id that refers to another partner in the same file), the tool’s new automatic two-pass import strategy handles this for you. It will automatically create all records in the first pass and then link the relationships in a second pass, removing the need for manual sorting or multiple import runs for a single file.
Why is one of my exported columns completely empty?¶
his can happen for two main reasons:
The field is genuinely empty for all records in your exported dataset.
There might be a typo in the field name you provided in the –fields argument.
To check for the second case, look at the console output when you run the export command. If the field name is invalid, odoo-data-flow will show a warning like this:
WARNING Field 'your_field_name' (base: 'your_field_name') not found on model 'res.partner'. An empty column will be created.
If you see this warning, correct the field name in your command and run the export again.