Quick Answer
80% of Odoo API failures stem from just 5 common errors: Access Denied (use API Keys, not passwords), Many2many write crashes (use tuple syntax), 404 Protocol errors (verify exact DB URL), timeouts on large batches (implement pagination), and ValidationError (check record state before writing). This guide provides exact Python code fixes for each.
Introduction: The Integration "Black Box"
Odoo's External API is a powerful gateway. It allows your e-commerce store, mobile app, or legacy software to "talk" to Odoo directly using standard XML-RPC or JSON-RPC.
But when it breaks, it breaks silently. You get a generic 500 Internal Server Error or a cryptic Fault 1 code, leaving developers staring at logs for hours.
In our experience auditing over 100+ integrations, we've found that 80% of API failures stem from just 5 common errors. This guide strips away the complexity and gives you the exact code fixes to get your data flowing again.
Error #1: The "Access Denied" Authentication Loop
Error: xmlrpc.client.Fault: <Fault 1: 'Access Denied'>
This is the "Hello World" of API errors. You send your credentials, but Odoo slams the door.
The Common Cause:
Most developers try to use their Account Password (the one used to log in to the UI) for the API. In Odoo 16, 17, and 18, if you have Two-Factor Authentication (2FA) or OAuth enabled, your regular password will not work.
The Fix: Generate a Dedicated API Key
Step 1: Log in to Odoo as the user you want to connect with
Step 2: Click on your profile picture → Preferences
Step 3: Go to the Account Security tab
Step 4: Click New API Key
Step 5: Use this long alphanumeric string as your password in the Python/PHP script
Python - Correct Authentication:
# DON'T do this:
password = "my_super_secret_password"
# DO this:
password = "7891b48590c29a59547d..." # Your Generated API Key
🔒 Security Tip: Never use the "Administrator" account for integrations. Create a dedicated "API User" with limited rights.
Error #2: The "Many2many" Write Crash
Error: ValueError: Wrong value for relation field
You are trying to add a Tag to a Contact or a Tax to an Invoice line. You send a list of IDs like [4, 8, 12], but Odoo crashes.
The Common Cause:
Odoo relation fields (One2many and Many2many) do not accept simple lists. They require a specific tuple syntax called "Special Commands."
The Fix: Use Odoo's 3-Element Tuple Format
❌ Wrong:
'tag_ids': [4, 5]
✓ Right:
'tag_ids': [(6, 0, [4, 5])]
Replaces all existing tags with tags 4 and 5
Cheat Sheet for Write Commands:
| Command | Action | Use Case |
|---|---|---|
| (4, ID) | Add existing record (Link) | Add one tag to a contact |
| (3, ID) | Remove record (Unlink) | Remove one tag from contact |
| (6, 0, [IDs]) | Replace entire list | Set exactly these tags |
Python - Adding a Tag to Contact:
# Adding a tag (ID 5) to a Contact
models.execute_kw(
db, uid, password,
'res.partner', 'write',
[[contact_id], {'category_id': [(4, 5)]}]
)
Error #3: The "ProtocolError" (404 Not Found)
Error: ProtocolError: <ProtocolError for website.com/xmlrpc/2/common: 404 Not Found>
You copy-pasted the URL from the documentation, but your script can't connect.
The Common Cause:
This is usually a Database Name or URL mismatch.
URL Issue: If you are using Odoo.sh or SaaS, your URL must be the exact database URL, not the redirect URL.
DB Name Issue: Odoo Online databases often have names like company-name-main-123456, not just company.
The Fix:
Step 1: Check your browser URL bar when logged in
Step 2: If you are on https://mycompany.odoo.com, your endpoint is https://mycompany.odoo.com/xmlrpc/2/common
Step 3: To find your exact DB Name, go to https://mycompany.odoo.com/web/database/selector
Error #4: Timeouts on Large Batches
Error: xmlrpc.client.Fault: <Fault 2: 'Transaction rolled back'>
Your script works fine for 10 records. But when you try to sync 5,000 products, it hangs for 60 seconds and then crashes, saving nothing.
The Common Cause:
Odoo has a hard time limit (often 60 or 900 seconds depending on hosting) for a single request. If your script doesn't finish in time, Odoo kills the process and rolls back the transaction.
The Fix: Pagination (Batching)
Never try to read or write 5,000 records in one call. Process in batches of 100 records.
Python - Safe Batch Processing:
# The Safe Way: Process in batches of 100
limit = 100
offset = 0
while True:
ids = models.execute_kw(
db, uid, password,
'product.template', 'search',
[[['type', '=', 'product']]],
{'limit': limit, 'offset': offset}
)
if not ids:
break
# Process these 100 IDs
process_products(ids)
offset += limit
Error #5: "ValidationError: The operation cannot be completed"
Error: odoo.exceptions.ValidationError
You try to update a Sales Order, but Odoo says "No."
The Common Cause:
You are violating a business rule. For example, trying to edit a Sales Order that is already in "Locked" or "Done" state. Odoo protects data integrity by blocking writes on finalized documents.
The Fix:
Check State First: If state == 'done', you usually cannot edit it via API
Solution A: Call a button method (like "Unlock") first before editing
Solution B: Create a refund/return instead of editing the original document
Error Quick Reference
| Error | Cause | Quick Fix |
|---|---|---|
| Access Denied | Using UI password with 2FA | Generate API Key |
| Many2many ValueError | Wrong list syntax | Use (6, 0, [IDs]) tuple |
| 404 ProtocolError | Wrong URL/DB name | Check exact URL in browser |
| Transaction Timeout | Too many records | Batch in 100s with pagination |
| ValidationError | Record is locked/done | Check state before writing |
Frequently Asked Questions
What is the difference between JSON-RPC and XML-RPC in Odoo?
Both do the same thing. XML-RPC is the standard, documented method for external scripts (Python, PHP, Java). JSON-RPC is used internally by the Odoo web client (JavaScript) and is faster for mobile apps, but it is less documented for external use.
How do I test my Odoo API connection without writing code?
Use Postman. You can configure a POST request to your Odoo XML-RPC endpoint. However, since XML-RPC is verbose, many developers prefer using a simple Python script in a Jupyter notebook for quick testing.
Why does my API user keep getting logged out?
If you are using a regular session ID instead of an API Key, the session will expire. Always use API Keys for long-running integrations; they do not expire.
What batch size should I use for Odoo API calls?
We recommend 100 records per batch as a safe default. For simple operations (just reading IDs), you can go up to 500. For complex operations (creating invoices with lines), stay at 50-100 to avoid timeouts.
How do I handle Many2one fields in Odoo API?
Many2one fields are simpler than Many2many. Just pass the integer ID directly: 'partner_id': 42. No tuple syntax needed. To clear the field, pass False.
Conclusion: Robust Integrations Require Error Handling
A good integration isn't one that just "works"; it's one that fails gracefully. By implementing proper batching, correct Many2many syntax, and secure authentication, you can build connectors that run reliably for years.
Stuck on an Error We Didn't Cover?
Don't waste another day on StackOverflow. Braincuber's integration experts can debug your script in a single session.
Book a 1-Hour API Debugging Session
Fix the bug, finish the project. Our experts will screen-share with you and resolve your integration issues live.
1-hour session • Screen sharing • Code fixes included
