Diagnose and fix common Evernote API errors. Use when encountering Evernote API exceptions, debugging failures, or troubleshooting integration issues. Trigger with phrases like "evernote error", "evernote exception", "fix evernote issue", "debug evernote", "evernote troubleshooting".
Install with Tessl CLI
npx tessl i github:jeremylongshore/claude-code-plugins-plus-skills --skill evernote-common-errors80
Does it follow best practices?
If you maintain this skill, you can automatically optimize it using the tessl CLI to improve its score:
npx tessl skill review --optimize ./path/to/skillValidation for skill structure
Comprehensive guide to diagnosing and resolving Evernote API errors, including EDAMUserException, EDAMSystemException, and EDAMNotFoundException.
Evernote uses three main exception types:
| Exception | When Thrown |
|---|---|
EDAMUserException | Client error - invalid input, permissions |
EDAMSystemException | Server error - rate limits, maintenance |
EDAMNotFoundException | Resource not found - invalid GUID |
Cause: Invalid ENML content or malformed data
// Error
{
errorCode: 1, // BAD_DATA_FORMAT
parameter: 'Note.content'
}
// Common causes and fixes:
// 1. Missing XML declaration
// Wrong:
'<en-note><p>Hello</p></en-note>'
// Correct:
`<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd">
<en-note><p>Hello</p></en-note>`
// 2. Forbidden HTML elements
// Wrong: contains <script>
`<en-note><script>alert('hi')</script></en-note>`
// Correct: remove scripts
`<en-note><p>Content only</p></en-note>`
// 3. Unclosed tags
// Wrong:
'<en-note><p>Hello<br></en-note>'
// Correct:
'<en-note><p>Hello</p><br/></en-note>'Fix: Validate ENML before sending:
function validateENML(content) {
const errors = [];
// Required declarations
if (!content.includes('<?xml version="1.0"')) {
errors.push('Missing XML declaration');
}
if (!content.includes('<!DOCTYPE en-note')) {
errors.push('Missing DOCTYPE');
}
if (!content.includes('<en-note>')) {
errors.push('Missing <en-note> root element');
}
// Forbidden elements
const forbidden = [
/<script/i, /<form/i, /<input/i, /<button/i,
/<iframe/i, /<object/i, /<embed/i, /<applet/i
];
forbidden.forEach(pattern => {
if (pattern.test(content)) {
errors.push(`Forbidden element: ${pattern.source}`);
}
});
// Forbidden attributes
if (/\s(class|id|onclick|onload|onerror)=/i.test(content)) {
errors.push('Forbidden attributes (class, id, event handlers)');
}
return { valid: errors.length === 0, errors };
}Cause: Missing required field
// Error
{
errorCode: 2, // DATA_REQUIRED
parameter: 'Note.title'
}
// Fix: Ensure required fields are set
const note = new Evernote.Types.Note();
note.title = 'Required Title'; // Cannot be null or empty
note.content = validENMLContent; // Cannot be nullCause: API key lacks required permissions
// Error
{
errorCode: 3, // PERMISSION_DENIED
parameter: 'NoteStore.shareNote'
}
// Causes:
// 1. API key doesn't have sharing permission
// 2. Trying to access business features without business API key
// 3. Accessing notes in shared notebooks without permission
// Fix: Request appropriate permissions when creating API key
// See: https://dev.evernote.com/doc/articles/permissions.phpCause: Invalid or expired authentication token
// Error
{
errorCode: 4, // INVALID_AUTH
parameter: 'authenticationToken'
}
// Fix: Check token validity
async function checkTokenValidity(client) {
try {
const userStore = client.getUserStore();
await userStore.getUser();
return { valid: true };
} catch (error) {
if (error.errorCode === 4) {
return {
valid: false,
reason: 'Token expired or revoked',
action: 'Re-authenticate via OAuth'
};
}
throw error;
}
}Cause: Token has passed expiration date
// Error
{
errorCode: 5, // AUTH_EXPIRED
parameter: 'authenticationToken'
}
// Tokens expire after 1 year by default
// Users can set shorter: 1 day, 1 week, 1 month
// Fix: Store and check expiration
function isTokenExpired(expirationTimestamp) {
return Date.now() > expirationTimestamp;
}
// When authenticating, save edam_expires:
// results.edam_expires contains expiration timestampCause: Account limits exceeded
// Error
{
errorCode: 6, // LIMIT_REACHED
parameter: 'Notebook.name'
}
// Account limits:
// - 250 notebooks max
// - 100,000 tags max
// - 100,000 notes max (business accounts)
// - Upload limits per month
// Fix: Check limits before creating
async function canCreateNotebook(noteStore) {
const notebooks = await noteStore.listNotebooks();
return notebooks.length < 250;
}Cause: Monthly upload quota exceeded
// Error
{
errorCode: 7, // QUOTA_REACHED
parameter: 'Note.content'
}
// Quotas vary by account type:
// - Basic: 60 MB/month
// - Premium: 10 GB/month
// - Business: 20 GB/month (per user)
// Check remaining quota
async function getRemainingQuota(userStore) {
const user = await userStore.getUser();
const accounting = user.accounting;
return {
uploadLimit: accounting.uploadLimit,
uploadLimitEnd: new Date(accounting.uploadLimitEnd),
uploaded: accounting.uploaded,
remaining: accounting.uploadLimit - accounting.uploaded
};
}Cause: Too many API calls per hour
// Error
{
errorCode: 19, // RATE_LIMIT_REACHED
rateLimitDuration: 300 // seconds until reset
}
// Fix: Implement exponential backoff
async function withRateLimitRetry(operation, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await operation();
} catch (error) {
if (error.errorCode === 19 && error.rateLimitDuration) {
console.log(`Rate limited. Waiting ${error.rateLimitDuration}s...`);
await sleep(error.rateLimitDuration * 1000);
continue;
}
throw error;
}
}
throw new Error('Max retries exceeded');
}
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));Cause: Evernote service is under maintenance
// Error
{
errorCode: 1, // UNKNOWN (with message about maintenance)
message: 'Service temporarily unavailable'
}
// Fix: Retry with backoff
async function withMaintenanceRetry(operation) {
const delays = [1000, 5000, 15000, 60000]; // Progressive delays
for (const delay of delays) {
try {
return await operation();
} catch (error) {
if (error.message?.includes('temporarily unavailable')) {
console.log(`Service maintenance. Retrying in ${delay / 1000}s...`);
await sleep(delay);
continue;
}
throw error;
}
}
throw new Error('Service unavailable - maintenance ongoing');
}Cause: Referenced resource doesn't exist
// Error
{
identifier: 'Note.guid',
key: '12345678-abcd-1234-efgh-invalid00000'
}
// Common scenarios:
// 1. Note was deleted
// 2. Note is in trash
// 3. Invalid GUID format
// 4. Note belongs to different user
// Fix: Handle gracefully
async function safeGetNote(noteStore, guid) {
try {
return await noteStore.getNote(guid, true, false, false, false);
} catch (error) {
if (error.identifier === 'Note.guid') {
console.log(`Note not found: ${guid}`);
return null;
}
throw error;
}
}// services/error-handler.js
const Evernote = require('evernote');
class EvernoteErrorHandler {
static handle(error) {
// EDAMUserException
if (error.errorCode !== undefined && error.parameter !== undefined) {
return this.handleUserException(error);
}
// EDAMSystemException
if (error.errorCode !== undefined && error.rateLimitDuration !== undefined) {
return this.handleSystemException(error);
}
// EDAMNotFoundException
if (error.identifier !== undefined) {
return this.handleNotFoundException(error);
}
// Unknown error
return {
type: 'UNKNOWN',
message: error.message || 'Unknown Evernote error',
recoverable: false,
original: error
};
}
static handleUserException(error) {
const codes = {
1: { name: 'BAD_DATA_FORMAT', action: 'Validate input data format' },
2: { name: 'DATA_REQUIRED', action: 'Provide required field' },
3: { name: 'PERMISSION_DENIED', action: 'Check API key permissions' },
4: { name: 'INVALID_AUTH', action: 'Re-authenticate user' },
5: { name: 'AUTH_EXPIRED', action: 'Token expired, re-authenticate' },
6: { name: 'LIMIT_REACHED', action: 'Account limit exceeded' },
7: { name: 'QUOTA_REACHED', action: 'Upload quota exceeded' }
};
const info = codes[error.errorCode] || { name: 'UNKNOWN', action: 'Check documentation' };
return {
type: 'USER_EXCEPTION',
code: error.errorCode,
name: info.name,
parameter: error.parameter,
action: info.action,
recoverable: [4, 5].includes(error.errorCode),
original: error
};
}
static handleSystemException(error) {
return {
type: 'SYSTEM_EXCEPTION',
code: error.errorCode,
rateLimitDuration: error.rateLimitDuration,
action: `Wait ${error.rateLimitDuration} seconds before retrying`,
recoverable: true,
original: error
};
}
static handleNotFoundException(error) {
return {
type: 'NOT_FOUND',
identifier: error.identifier,
key: error.key,
action: 'Resource does not exist or was deleted',
recoverable: false,
original: error
};
}
}
module.exports = EvernoteErrorHandler;const ErrorHandler = require('./services/error-handler');
async function createNoteSafely(noteStore, note) {
try {
return await noteStore.createNote(note);
} catch (error) {
const handled = ErrorHandler.handle(error);
console.error('Evernote error:', handled.name || handled.type);
console.error('Parameter:', handled.parameter || handled.identifier);
console.error('Action:', handled.action);
if (handled.recoverable) {
console.log('Error is recoverable');
if (handled.rateLimitDuration) {
await sleep(handled.rateLimitDuration * 1000);
return noteStore.createNote(note);
}
}
throw error;
}
}| Code | Exception | Cause | Fix |
|---|---|---|---|
| 1 | UserException | Bad data format | Validate ENML |
| 2 | UserException | Missing required field | Add required field |
| 3 | UserException | Permission denied | Check API key |
| 4 | UserException | Invalid auth | Re-authenticate |
| 5 | UserException | Auth expired | Refresh token |
| 6 | UserException | Limit reached | Check account limits |
| 7 | UserException | Quota reached | Check upload quota |
| 19 | SystemException | Rate limit | Wait rateLimitDuration |
| - | NotFoundException | GUID not found | Verify resource exists |
For debugging tools and techniques, see evernote-debug-bundle.
9659b78
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.