evernote-common-errors

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Evernote Common Errors

Evernote常见错误

Overview

概述

Comprehensive guide to diagnosing and resolving Evernote API errors, including EDAMUserException, EDAMSystemException, and EDAMNotFoundException.
本文是诊断和解决Evernote API错误的综合指南,涵盖EDAMUserException、EDAMSystemException和EDAMNotFoundException三种异常类型。

Prerequisites

前置条件

  • Basic Evernote SDK setup
  • Understanding of Evernote data model
  • 基础的Evernote SDK配置
  • 了解Evernote数据模型

Error Types

错误类型

Evernote uses three main exception types:
ExceptionWhen Thrown
EDAMUserException
Client error - invalid input, permissions
EDAMSystemException
Server error - rate limits, maintenance
EDAMNotFoundException
Resource not found - invalid GUID
Evernote主要使用三种异常类型:
异常类型触发场景
EDAMUserException
客户端错误 - 输入无效、权限不足
EDAMSystemException
服务器错误 - 速率限制、维护中
EDAMNotFoundException
资源不存在 - GUID无效

EDAMUserException Errors

EDAMUserException错误

BAD_DATA_FORMAT

BAD_DATA_FORMAT

Cause: Invalid ENML content or malformed data
javascript
// 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:
javascript
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 };
}
原因: ENML内容无效或数据格式错误
javascript
// 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>'
修复方案: 在发送前验证ENML:
javascript
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 };
}

DATA_REQUIRED

DATA_REQUIRED

Cause: Missing required field
javascript
// 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 null
原因: 缺少必填字段
javascript
// 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 null
修复方案: 确保必填字段已设置

PERMISSION_DENIED

PERMISSION_DENIED

Cause: API key lacks required permissions
javascript
// 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.php
原因: API密钥缺少必要权限
javascript
// 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.php
修复方案: 创建API密钥时申请相应权限 // 参考:https://dev.evernote.com/doc/articles/permissions.php

INVALID_AUTH

INVALID_AUTH

Cause: Invalid or expired authentication token
javascript
// 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;
  }
}
原因: 认证令牌无效或已过期
javascript
// 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;
  }
}
修复方案: 检查令牌有效性

AUTH_EXPIRED

AUTH_EXPIRED

Cause: Token has passed expiration date
javascript
// 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 timestamp
原因: 令牌已过有效期
javascript
// 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 timestamp
修复方案: 存储并检查过期时间 // 认证时,保存edam_expires字段: // results.edam_expires包含过期时间戳

LIMIT_REACHED

LIMIT_REACHED

Cause: Account limits exceeded
javascript
// 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;
}
原因: 超出账户限制
javascript
// 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;
}
修复方案: 创建前检查账户限制

QUOTA_REACHED

QUOTA_REACHED

Cause: Monthly upload quota exceeded
javascript
// 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
  };
}
原因: 超出月度上传配额
javascript
// 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
  };
}
修复方案: 查询剩余配额

EDAMSystemException Errors

EDAMSystemException错误

RATE_LIMIT_REACHED

RATE_LIMIT_REACHED

Cause: Too many API calls per hour
javascript
// 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));
原因: 每小时API调用次数过多
javascript
// 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));
修复方案: 实现指数退避重试机制

SYSTEM_MAINTENANCE

SYSTEM_MAINTENANCE

Cause: Evernote service is under maintenance
javascript
// 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');
}
原因: Evernote服务正在维护
javascript
// 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');
}
修复方案: 退避重试

EDAMNotFoundException Errors

EDAMNotFoundException错误

Cause: Referenced resource doesn't exist
javascript
// 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;
  }
}
原因: 引用的资源不存在
javascript
// 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;
  }
}
修复方案: 优雅处理错误

Error Handling Service

错误处理服务

javascript
// 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;
javascript
// 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;

Usage Example

使用示例

javascript
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;
  }
}
javascript
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;
  }
}

Output

输出结果

  • Understanding of all Evernote exception types
  • Error code reference with solutions
  • Reusable error handling service
  • Rate limit retry implementation
  • 了解所有Evernote异常类型
  • 带解决方案的错误码参考
  • 可复用的错误处理服务
  • 速率限制重试实现

Quick Reference

快速参考

CodeExceptionCauseFix
1UserExceptionBad data formatValidate ENML
2UserExceptionMissing required fieldAdd required field
3UserExceptionPermission deniedCheck API key
4UserExceptionInvalid authRe-authenticate
5UserExceptionAuth expiredRefresh token
6UserExceptionLimit reachedCheck account limits
7UserExceptionQuota reachedCheck upload quota
19SystemExceptionRate limitWait rateLimitDuration
-NotFoundExceptionGUID not foundVerify resource exists
错误码异常类型原因修复方案
1UserException数据格式错误验证ENML
2UserException缺少必填字段添加必填字段
3UserException权限不足检查API密钥
4UserException认证无效重新认证
5UserException认证过期刷新令牌
6UserException超出账户限制检查账户限制
7UserException超出上传配额检查上传配额
19SystemException速率限制等待rateLimitDuration秒后重试
-NotFoundExceptionGUID不存在验证资源是否存在

Resources

参考资源

Next Steps

下一步

For debugging tools and techniques, see
evernote-debug-bundle
.
如需调试工具和技术,请查看
evernote-debug-bundle