agentsclimarketplace

Onenote common errors

Skill jeremylongshore/claude-code-plugins-plus-skills/plugins/saas-packs/onenote-pack/skills/onenote-common-errors

'Decode and fix every common OneNote Graph API error with root cause analysis.From its SKILL.md

Install
npx -y skills add jeremylongshore/claude-code-plugins-plus-skills --skill onenote-common-errors

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

What its file declares

Copied from the file, not written here

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

12.8 KB, ~2.9k tokens by cl100k_base, as published. Nobody here has run it

OneNote Common Errors

Overview

A complete error decoder for the OneNote Graph API. Each HTTP status code has multiple possible root causes — this skill maps every cause, provides diagnostic steps, and gives fix-it code. Special attention to the two trickiest errors: 403 (which could mean wrong permissions OR deprecated app-only auth) and 200 with empty body (silent upload failure that causes data loss).

Prerequisites

  • A OneNote Graph API integration that is returning errors
  • Access to application logs or the ability to add logging
  • Familiarity with the Graph API request/response format

Instructions

Complete Error Reference Table

CodeError NamePossible CausesFix
400Bad Request(1) Invalid XHTML — unclosed tags, bad encodingValidate HTML with XML parser before sending
(2) Bad notebook name — empty or duplicate displayNameCheck for existing notebooks, use unique names
(3) Malformed JSON in PATCH bodyValidate JSON structure matches update spec
(4) Missing <title> in page HTMLAlways include <head><title>...</title></head>
(5) Invalid $filter OData expressionCheck OData query syntax
403Forbidden(1) App-only auth (deprecated March 2025)Switch to delegated auth (DeviceCodeCredential)
(2) Missing permission scopeAdd Notes.ReadWrite in Azure Portal, re-consent
(3) User doesn't own the notebookUse /users/{id}/onenote/ for shared notebooks
(4) Admin consent required but not grantedAdmin must grant consent in Azure Portal
(5) Conditional access policy blocking appCheck Azure AD conditional access policies
404Not Found(1) Page/section/notebook ID is wrongRe-fetch parent resource to get correct IDs
(2) Resource was deletedUse $filter=isDeleted eq true if available
(3) Wrong URL formatVerify endpoint: /me/onenote/ not /me/notes/
(4) User context mismatch — querying another user's notes without delegationUse /users/{userId}/onenote/ with correct permissions
429Too Many Requests(1) Per-user limit: 600 requests / 60 secondsParse Retry-After header, wait exact seconds
(2) Per-tenant limit: 10,000 requests / 10 minutesReduce concurrency, use batch requests
(3) Burst of requests from multiple users in same tenantImplement per-tenant rate limit tracking
500Internal Server Error(1) Graph service internal failureRetry with exponential backoff
(2) Malformed request that passes validation but fails processingCheck request body against API reference
502Bad Gateway(1) Upstream OneNote service unavailableRetry after 5-10 seconds
(2) Token expiration during processingRefresh token and retry
507Insufficient Storage(1) Per-section page limit exceeded (~5000 pages)Create a new section, archive old pages
(2) User OneDrive storage quota hitCheck storage quota in OneDrive settings

The 403 Trap: App-Only Auth Deprecation

This is the single most common production issue since March 2025. If your code uses ClientSecretCredential (Node) or client_secret (Python) for OneNote calls, every request returns 403 regardless of permission scope.

How to diagnose:

// Check if you're using the deprecated auth pattern
// SEARCH your codebase for these — any match means you need to migrate:
// - ClientSecretCredential
// - client_secret
// - AZURE_CLIENT_SECRET
// - ConfidentialClientApplication (for OneNote specifically)

// If found, the fix is:
// BEFORE (broken after March 2025):
import { ClientSecretCredential } from "@azure/identity";
const credential = new ClientSecretCredential(tenantId, clientId, clientSecret);

// AFTER (correct):
import { DeviceCodeCredential } from "@azure/identity";
const credential = new DeviceCodeCredential({ clientId, tenantId });

The 200 Trap: Silent Upload Failure

This error does not appear in any error table because the HTTP status is 200. Files larger than approximately 4MB return 200 OK with an empty response body. The page is never created.

// DETECTION: Always check the response body after page creation
const response = await client
  .api(`/me/onenote/sections/${sectionId}/pages`)
  .header("Content-Type", "text/html")
  .post(htmlContent);

// This looks successful but the page was never created:
if (!response || !response.id) {
  console.error("SILENT FAILURE: 200 OK but no page ID returned");
  console.error(`Payload size: ${Buffer.byteLength(htmlContent, "utf-8")} bytes`);
  // Fix: reduce payload size below 4MB, use URL references for images
  // instead of inline base64 data
}

The 404 Trap: Deleted Pages in List Results

GET /me/onenote/sections/{id}/pages can return pages that have been recently deleted. When you try to GET /me/onenote/pages/{id}/content on these pages, you get 404.

// Defensive page content retrieval
async function getPageContentSafe(client: Client, pageId: string) {
  try {
    return await client.api(`/me/onenote/pages/${pageId}/content`).get();
  } catch (error: any) {
    if (error.statusCode === 404) {
      console.warn(`Page ${pageId} listed but not accessible (likely deleted)`);
      return null;
    }
    throw error;
  }
}

Diagnostic Code: Extract Request ID and Diagnostics

When contacting Microsoft support, they need the request-id header from the failed response. The x-ms-ags-diagnostic header contains internal routing information.

function logGraphError(error: any): void {
  const headers = error.headers ?? new Map();
  const requestId = headers.get?.("request-id") ?? "unavailable";
  const diagnostics = headers.get?.("x-ms-ags-diagnostic") ?? "";
  const dateHeader = headers.get?.("date") ?? new Date().toISOString();

  console.error("=== OneNote Graph API Error ===");
  console.error(`Status:     ${error.statusCode}`);
  console.error(`Code:       ${error.code}`);
  console.error(`Message:    ${error.message}`);
  console.error(`Request-ID: ${requestId}`);
  console.error(`Date:       ${dateHeader}`);

  if (diagnostics) {
    try {
      const parsed = JSON.parse(diagnostics);
      console.error(`Server:     ${parsed.serverInfo?.dataCenter ?? "unknown"}`);
    } catch {
      console.error(`Diagnostics: ${diagnostics}`);
    }
  }

  console.error("==============================");
  console.error(
    `For Microsoft support, provide: request-id=${requestId}, date=${dateHeader}`
  );
}
# Python equivalent
def log_graph_error(error) -> None:
    """Extract diagnostic info from Graph API error for support tickets."""
    request_id = getattr(error, "request_id", "unavailable")
    status = getattr(error, "status_code", "unknown")
    message = getattr(error, "message", str(error))

    print("=== OneNote Graph API Error ===")
    print(f"Status:     {status}")
    print(f"Message:    {message}")
    print(f"Request-ID: {request_id}")
    print("===============================")
    print(f"For Microsoft support: request-id={request_id}")

Permission Misconfiguration Table

SymptomLikely MisconfigurationFix
403 on all OneNote callsUsing ClientSecretCredential (app-only deprecated)Switch to DeviceCodeCredential
403 on write operations onlyHave Notes.Read but missing Notes.ReadWriteAdd Notes.ReadWrite scope, re-consent
403 on shared notebooksHave Notes.ReadWrite but missing Notes.ReadWrite.AllAdd .All scope for shared notebook access
403 after admin policy changeConditional access policy blocks the appCheck with Azure AD admin, add app to policy exclusion
403 on first request onlyAdmin consent required but user cannot consentAdmin must grant consent in Azure Portal
401 after token was workingToken expired (default 1-hour lifetime)Implement token refresh, use MSAL token cache
400 on PATCH pageJSON body missing target or action fieldReview update page spec

TypeScript Error Handler with Structured Logging

type ErrorSeverity = "warn" | "error" | "fatal";

interface DiagnosticResult {
  severity: ErrorSeverity;
  category: string;
  userMessage: string;
  devAction: string;
  retryable: boolean;
}

function diagnoseOneNoteError(statusCode: number, errorBody?: any): DiagnosticResult {
  const code = errorBody?.error?.code ?? "";

  switch (statusCode) {
    case 400:
      return {
        severity: "error",
        category: "invalid_request",
        userMessage: "The request was malformed.",
        devAction: code === "20117"
          ? "Notebook name already exists. Use a unique displayName."
          : "Validate XHTML and JSON request body against API spec.",
        retryable: false,
      };
    case 403:
      return {
        severity: "fatal",
        category: "auth_or_permissions",
        userMessage: "Access denied to OneNote resource.",
        devAction: "Check: (1) using delegated auth not app-only? " +
          "(2) correct permission scope? (3) admin consent granted?",
        retryable: false,
      };
    case 404:
      return {
        severity: "warn",
        category: "resource_not_found",
        userMessage: "The requested notebook, section, or page was not found.",
        devAction: "Re-fetch parent resource IDs. Page may have been deleted.",
        retryable: false,
      };
    case 429:
      return {
        severity: "warn",
        category: "rate_limit",
        userMessage: "Too many requests. Slowing down.",
        devAction: "Parse Retry-After header. Consider batch requests.",
        retryable: true,
      };
    case 507:
      return {
        severity: "error",
        category: "storage_quota",
        userMessage: "Storage limit reached.",
        devAction: "Check section page count (~5000 limit) and OneDrive quota.",
        retryable: false,
      };
    default:
      return {
        severity: statusCode >= 500 ? "error" : "warn",
        category: "server_error",
        userMessage: "A server error occurred. Retrying.",
        devAction: "Retry with exponential backoff. Log request-id for support.",
        retryable: statusCode >= 500,
      };
  }
}

Output

After using this skill you will be able to:

  • Immediately identify the root cause of any OneNote Graph API error
  • Distinguish between permission errors and deprecated auth patterns
  • Detect silent upload failures that return 200 OK
  • Extract diagnostic headers for Microsoft support escalation
  • Build structured error handling that categorizes and routes errors correctly

Error Handling

This entire skill IS error handling documentation. For implementation of retry logic and rate limit handling, see onenote-sdk-patterns.

Examples

Quick error check script:

# Test connectivity and permissions in one command
curl -s -w "\nHTTP %{http_code}" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  "https://graph.microsoft.com/v1.0/me/onenote/notebooks" \
  | tail -1
# 200 = working, 401 = token issue, 403 = permissions/auth type, 404 = wrong endpoint

Decode a specific error in logs:

// When you see this in logs:
// { statusCode: 403, code: "40004", message: "Insufficient privileges" }
// Run the diagnostic:
const result = diagnoseOneNoteError(403, { error: { code: "40004" } });
// result.devAction → "Check: (1) using delegated auth not app-only? ..."

Resources

Next Steps

  • See onenote-sdk-patterns for production retry and rate limit middleware
  • See onenote-install-auth to fix authentication and permission issues
  • See onenote-local-dev-loop to test error handling with mock responses

What ships with it: 1 file

1.9 KB alongside SKILL.md

references/

Keep looking

Skills are one crate of 326,144. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.