SuperAPI AI Directory

record-bug-fix-memory

Agents & models

View repository

Updated 10-16 09:52

About this skill

Record Bug Fix Memory

Overview

Use this skill to distill completed troubleshooting results into reusable long-term memory.

The goal is to preserve the root cause, effective fix path, incorrect assumptions, and verification evidence so that future agents do not repeat the same detours.

Core principle: record the decision chain, not a running log.


When to Use

Use this skill in the following scenarios:

  • The user asks to update AI memory documents, record lessons learned, supplement incident records, or write a retrospective summary.
  • The bug has been reproduced, and the effective fix path is clear.
  • This lesson is repository-specific knowledge and should be visible to future agents.
  • The conclusion needs to be synced to local MCP memory, such as Memorix.

Do not use this skill in the following cases:

  • The bug is still under investigation, and the root cause has not been confirmed.
  • What the user is asking for is a fix implementation, not experience distillation.
  • You only have guesses, fragmentary evidence, or temporary workarounds.

Prerequisite Inputs

Before starting to write the memory, you must be able to answer the following six questions:

  1. From the user's perspective, what is the surface symptom?
  2. What is the actual root cause?
  3. Which incorrect assumption or misleading signal wasted time?
  4. Which specific change ultimately fixed the problem?
  5. What verification proves the fix holds?
  6. Where should this memory be written?

If any question cannot be answered, finish troubleshooting first, and do not write the memory prematurely.


Where to Write

  • Repository-level, reusable rules: write to the root-level CLAUDE.md、AGENTS.md、GEMINI.md
  • Cross-session local memory: write to Memorix, with type gotcha、decision or problem-solution
  • Package-level prompts, plans, reports: write to them only when the user explicitly requests it

Default rule: as long as this lesson will affect future agents across the entire repository, prioritize writing it into the three root-level AI memory documents, and do not bury it in package-level notes.


What to Record

Each memory must cover at least these six things:

  1. Problem symptom: from the user's perspective, what is broken
  2. Root cause: where the real error is
  3. Key clue: which signal pulled the problem back from an illusion to the real root cause
  4. Effective fix: the change that truly solved the problem
  5. Verification method: evidence proving the fix succeeded
  6. Follow-up constraints: what future agents must check first and what to avoid

Memory Template

Use a concise structure oriented toward future reuse:

  • 问题现象:...
  • 根因:...
  • 关键误导点:...
  • 有效修复:...
  • 验证方式:...
  • 后续约束:...

These sentences should help future agents quickly do the right thing, rather than retelling the complete troubleshooting process.


Repository-Level Knowledge Base

When the user asks to "supplement AI memory", do not just write the surface conclusion of the current bug. First check whether this problem falls into an existing incident pattern in the repository, then merge the corresponding lesson into the memory.

Reading hint: Each incident below uses a bolded dimension heading + a separate paragraph formatting for easy scanning; for similar issues, please add under the corresponding entrysupplement, to avoid opening a new paragraph repeatedly.


packages/vue-element-cui of vite@8 build incident

Issue symptoms

  • During the build phase, a vite:css-post of path type error is thrown, usually occurring during CSS asset artifact processing.

Actual root cause

  • rollupOptions.output.assetFileNames directly returns assetInfo.name, and when the CSS asset name is missing it returns undefined。

Effective fix

  • Do not downgrade dependencies, do not change dependency versions; prioritize adding a fallback value to the build configuration, for example assetInfo.name ?? "assets/[name][extname]"。

Key takeaway

  • When writing incident records in the future, it must be made clear that this is a "build configuration missing a fallback value" problem, rather than simply writing it as "vite version incompatibility".

Follow-up constraints

  • When encountering the same type of problem again, first check the fallback return value of the build configuration, and do not immediately think of downgrading the toolchain.

packages/vue-element-cui-nuxt of nuxt dev startup incident

Issue symptoms

  • The documentation site cannot be started directly in development mode, reporting missing .nuxt artifacts, missing component library style artifacts, or the appearance of #app-manifest -related errors.

Actual root cause

  • Incorrectly assuming that workspace dependencies have already been pre-built, and also incorrectly assuming that the .nuxt directory exists in advance.

Effective fix

  • Add dev/build to nuxt prepare as a prerequisite; configure source aliases for @eams-monorepo/vue-element-cui and @eams-monorepo/vue-element-cui/styles ; explicitly disable the currently unstable experimental.appManifest。

Key takeaway

  • When writing memory in the future, it must point out the constraint that "the documentation site development mode directly consumes source code", rather than only recording "just add a prepare and it will be fine".

Follow-up constraints

  • Do not base the startup of the documentation site on the premise that the component library dist already exists.

packages/vue-element-cui-nuxt documentation site client hydration incident

Issue symptoms

  • Dark mode cannot be toggled, and clicking to collapse the sidebar has no effect. Do not prejudicially attribute this kind of interaction failure to styles.

Actual root cause

  • Nuxt client hydration was interrupted by a dependency entry compatibility issue. The first trustworthy signal is the browser console error dayjs.min.js does not provide an export named 'default', and subsequently it also cascades into @braintree/sanitize-url、debug、mermaid ESM/CJS compatibility issues.

Effective fix

  • Keep extends: ["shadcn-docs-nuxt"] unchanged; prioritize making compatibility corrections at the Vite layer of nuxt.config.ts , for example dayjs -> dayjs/esm/index.js、mermaid -> mermaid/dist/mermaid.esm.mjs、debug -> ./shims/debug.ts, and supplement vite.optimizeDeps.include、vite.resolve.dedupe = ["dayjs"]、vite.ssr.noExternal = ["debug"];tailwind.config.js only as a content scanning fallback, and do not treat styles as the root cause.

Key takeaway

  • When writing memory in the future, it must be made clear that "the first trustworthy clue comes from the Chrome MCP console, not from the visual symptoms themselves".

Follow-up constraints

  • The troubleshooting order is fixed as "first console module errors, then dependency entries, then the style layer".

packages/vue-element-cui-nuxt stable startup baseline

Issue symptoms

  • The project clearly used to run, but after subsequent modifications it was changed until it could no longer start.

Actual root cause

  • The stable configuration was changed arbitrarily, especially continuing to make spreading modifications after the user had already confirmed that "it currently runs".

Effective fix

  • Record the stable startup state confirmed by the user as the baseline, including the streamlined dependency set,extends: ["shadcn-docs-nuxt"], monolingual zh-CN i18n、ogImage.enabled = false、icon.clientBundle.scan = true、vite.ssr.noExternal and other minimal viable combinations.

Key memory points

  • When writing memories in the future, in addition to writing "how to fix it", you must also write "which configurations should not be touched casually".

Follow-up constraints

  • Any subsequent troubleshooting and optimization must be premised on a stable baseline, to avoid breaking the project again.

packages/vue-element-cui-nuxt monolingual documentation and i18n misuse issues

Historical phenomenon

  • The i18n logic in the template inheritance chain once caused the /components page to show errors like Cannot read properties of undefined (reading children) , and also brought redundant locale path handling.

Common root cause

  • A monolingual documentation site should not unconditionally inherit the real multilingual runtime paths.

Key memory points

  • When writing memories in the future, clearly distinguish whether the "compat override path" or the "explicit monolingual defaultLocale/locales route" was adopted at the time, and do not mix different historical fixes into one conclusion.

Follow-up constraints

  • If the documentation site is essentially a monolingual site, it must be emphasized when recording that "do not treat multilingual runtime paths as the default premise".

simple-git-hooks hooks installed into a fake .git directory caused lint-staged to never trigger

Problem phenomenon

  • Every time git commit , lint-staged and commitlint were not triggered, staged files were not formatted, and commit messages were not validated.

Actual root cause

  • The Git repository root directory is at 01s-2603-13eams/(.git at this level), while the pnpm monorepo workspace has in its subdirectory eams-frontend-monorepo/。eams-frontend-monorepo/ a fake .git directory (containing only the hooks/ subdirectory, with no HEAD, config, etc.),simple-git-hooks when postinstall searches upward from the monorepo directory for .git, it first hit this fake directory, so the hooks were installed into eams-frontend-monorepo/.git/hooks/. But when Git executes a commit, what it looks for is the real 01s-2603-13eams/.git/hooks/(which only contains .sample files), so the hooks were never executed.

Key clues

  • git rev-parse --git-dir returns 01s-2603-13eams/.git, while ls eams-frontend-monorepo/.git/ has only one hooks/ subdirectory and no git metadata files, confirming that this is the fake simple-git-hooks created by .gititself. Comparing with the real .git/hooks/ directory—it contains no non- .sample hook files, directly confirming that the hooks were installed in the wrong place.

Effective fix

  • Three-step combined fix: (1) set git config core.hooksPath eams-frontend-monorepo/.git/hooks, so that Git reads hooks from the monorepo's hooks directory; (2) update simple-git-hooks.mjs, add the cd eams-frontend-monorepo prefix to the hook commands, so that npx can find dependencies and configuration under the monorepo directory; (3) the commit-msg hook uses ROOT=$(pwd) to first save the absolute path of the repository root, and after cd uses "$ROOT/$1" to assemble the full path of the commit message file (because $1 is a path relative to the repository root, and will become invalid after cd).

Verification method

  • git commit --allow-empty -m "test: hook trigger test" after seeing lint-staged output → No staged files found., commitlint also did not reject valid messages, confirming that both hooks were triggered normally.

Follow-up constraints

  • When the Git repository root and the monorepo workspace are not at the same level, you must check whether git rev-parse --git-dir and simple-git-hooks actually write hooks to the same location. Do not assume .git directory and package.json are on the same level. Deleting the fake .git is invalid—simple-git-hooks will be recreated, and it must be used together with core.hooksPath .

packages/vue-element-cui-nuxt MDC documentation icon loss incident (prettier accidental formatting)

Problem symptoms

  • On the documentation site /getting-started、/components、/guidelines、/updates all icons in the page cards disappeared, and props such astitle:、icon:、to: became plain text rendered directly on the page.

Actual root cause

  • prettier When formatting .md files, it automatically inserts a blank line between the MDC component declaration line (such as ::card) and the YAML frontmatter start marker (---). The MDC parser requires the two to be adjacent with no blank line; once there is a blank line,--- is parsed as a <hr> tag, all YAML content becomes paragraph text, and all props become invalid.

Key misleading point

  • At first it was thought that the icon bundle did not include the corresponding icon names, or that the SmartIcon component was missing, and time was spent checking the icon library configuration. You should first look at the HTML source—there is no icon element in the HTML at all, which shows that the props were never parsed.

Effective fix

  • (1) Create a new .prettierignore, add packages/vue-element-cui-nuxt/content/**/*.md; (2) in the prettier.config.mjs of overrides , add requirePragma: true for that path as a double safeguard; (3) manually restore all ::card\n---damaged by formatting (remove the blank lines in between).

Verification method

  • Invoke-WebRequest http://localhost:3001/getting-started The HTML returned by i-lucide:download、i-lucide:rocket、i-lucide:life-buoy、i-lucide:arrow-left-right contains the four icon classes.

Follow-up constraints

  • MDC content files must never be formatted by prettier;.prettierignore must cover all nuxt content directories; when troubleshooting disappearing icons, first check whether an icon element exists in the HTML source, rather than checking the icon library configuration first.

packages/vue-element-cui-nuxt of ::demo-playground rendering failure incident (MDC container syntax error, 2026-03)

Problem symptoms

  • Multiple component documentation pages showed raw text such as ::demo-playground、title:、#preview、#code rendered directly; the browser console showed Hydration completed but contains mismatches and a large number of hydration node mismatch warnings.

Actual root cause

  • demo-playground The container was not written according to MDC syntax. Typical errors include: (1) writing it as ## ::demo-playground(treated as a heading); (2) incorrect frontmatter order (title/description first,--- after); (3) mismatched container opening and closing markers.

Key misleading point

  • It is easy to first suspect the DemoPlayground component implementation or Nuxt dependency compatibility issues. In fact, the first high-value clue is that “raw marker text appears in the body + hydration mismatch appears at the same time,” and you should first go back and check the markdown container syntax.

Effective fix

  • Unify all example blocks as ::demo-playground + immediately followed by --- frontmatter + :: closing, and keep #preview and #code inside the container; after batch modification, sample and regress multiple routes.

Verification method

  • In Chrome MCP, passing requires three points: (1) no hydration mismatch errors in the console; (2) the page body no longer shows ::demo-playground/#preview/#code/title: raw text; (3) the demo title and description (from frontmatter) render normally.

Follow-up constraints

  • When adding new demo documentation later, it is forbidden to use ## ::demo-playground; do not reorder the frontmatter; batch replacement scripts may only modify the target container fragment, and you must sample first before doing a full run to avoid accidentally changing other ::: containers.

packages/vue-element-cui-nuxt Nuxt SSR i18n version conflict incident (pnpm dependency hoisting)

Symptoms

  • nuxt dev After startup, all pages return a 500 error, with the error message being Error: (0, __vite_ssr_import_0__.registerMessageResolver) is not a function。

Actual root cause

  • @intlify/core-base Multiple versions exist (9.1.9 and 11.x) simultaneously in the dependency tree.shamefully-hoist=false causes pnpm to manage dependencies in isolated mode, and during Vite SSR resolution it hit the old version 9.1.9 (missing registerMessageResolver), rather than the 11.x version required by vue-i18n@11.x . After upgrading shamefully-hoist=true , the old version sass@1.26.8 was hoisted instead, causing sass.initAsyncCompiler is not a function。

Key misleading points

  • Multiple attempts were made with vite.ssr.noExternal、vite.resolve.alias、vite.resolve.dedupe and other nuxt.config.ts configurations, all of which were ineffective directions; the correct direction is to force pnpm to use a single version across the entire workspace, rather than bypassing it at the Vite layer.

Effective fix

  • (1) In .npmrc , change it to shamefully-hoist=true; (2) In pnpm-workspace.yaml 's overrides , add "@intlify/core-base": "11.3.0"、"@intlify/shared": "11.3.0"、"sass": "^1.98.0"; (3) In the root package.json , upgrade vue-i18n to "11.3.0"; (4) Run pnpm install in a terminal outside Cursor to make the overrides take effect.

Verification method

  • The Nuxt dev server starts without a 500 error, and all pages return 200 OK; innode_modules/@intlify/core-base/package.json , the version field is 11.3.0。

Follow-up constraints

  • When encountering a Nuxt SSR is not a function error, first use pnpm why <package> to check whether multiple version instances exist, then force a single version through pnpm-workspace.yaml 's overrides ; do not make changing nuxt.config.ts 's Vite-layer configuration your first reaction.

Cursor IDE holding .node native file lock causing pnpm install to fail

Symptoms

  • When running pnpm install in Cursor's built-in terminal, it reports EPERM: operation not permitted, unlink 'node_modules/@oxc-parser/binding-win32-x64-msvc/parser.win32-x64-msvc.node', the installation rolls back, and dependency changes cannot take effect.

Actual root cause

  • Cursor IDE's TypeScript language service process (tsserver) holds a Windows file lock on the @oxc-parser native .node file, and pnpm cannot delete that file to complete the dependency update, causing the entire installation transaction to roll back.

Effective fix

  • Run pnpm installin a terminal outside Cursor (such as PowerShell or system CMD) to bypass the IDE file lock.

Verification method

  • After pnpm install finishes in the external terminal, there is no EPERM error, andpnpm-lock.yaml is updated correctly.

Follow-up constraints

  • When updating any dependency involving a native Node.js addon in this monorepo (such as @oxc-parser、esbuild、@swc/*), you must run pnpm installin a terminal outside Cursor; Cursor's built-in terminal is only for reading logs, not for executing install.

Repository root .gitattributes and eol=lf causing CRLF/LF "ghost" differences (2026-03)

Symptoms

  • For example, eams-frontend-monorepo/README.md on multiple f1-* sub-branchesalways shows as modified (M), and it does not disappear when switching branches, blocking merges;git diff Often only the whole-file "line ending change" is shown with no substantive content difference.

Actual root cause

  • Root directory .gitattributes already specifies text files eol=lf, and Git writes the working tree as LF on checkout, butthe historical blob of that file in each branch's index is still CRLF; the line-ending policy of the index and the working tree are inconsistent, creating a persistent dirty state.

Key misleading points

  • Mistaken for "a single branch not saved" or "the IDE messing things up"; changing the file on only one branch is not enough,every branch whose index still contains CRLF must be git add --renormalize and then committed, otherwise it reappears as soon as you switch back.

Effective fix

  • Run git add --renormalize <path>on the path (or the whole repository as needed, git add --renormalize .) and commit, so that the object database is consistent with .gitattributes ; in the monorepo eams-frontend-monorepo/.editorconfig 's [*] , add end_of_line = lfto reduce new files defaulting to CRLF on Windows. When gathering changes from each sub-branch into f1 , the merge commit message must pass commitlint, using forms such as chore: merge <branch> into f1 , and avoid using illegal types (such as merge:) that cause the merge not to complete.

Verification method

  • On multiple f1-* branches, after git checkout , git status has no such file;git diff is empty for that path.

Follow-up constraints

  • After introducing or tightening eol=lf , if "text files that are forever M" appear, first check git diff to see whether it is only CRLF↔LF and git add --renormalize, and do not first make large-scale changes to business code; before batch-merging sub-branches into the main branch, confirm that the commit messages comply with this repository's Conventional Commits rules.

packages/vue-element-cui-nuxt dev warning cleanup experience

Historical phenomenon

  • Even if the page can open,nuxt dev may still contain warnings for i18n, OG Image, Icon, Sass, etc.

Actual root cause

  • This is usually not a single-point problem, but the accumulation of multiple small compatibility issues, such as missing defaultLocale, same-named composables overlapping with auto-imports, calling defineOgImageComponent()even though it is not enabled, missing local lucide collections, styles still using global mix()。

Effective fix

  • Explicitly complete the monolingual i18n configuration; avoid duplicate auto-imports of same-named helpers;ogImage.enabled = false when doing so, remove the defineOgImageComponent() call via page overrides instead of forcibly enabling the module; install @iconify-json/lucide; migrate Sass's mix() to color.mix()。

Key memory points

  • When writing memory in the future, explain that warning cleanup must be based on new logs from a "single fresh dev process", not on guesses pieced together from old logs.

Follow-up constraints

  • When verifying conclusions, prioritize recording whether fresh dev.stderr is empty, whether the page HTTP is 200, and whether the Chrome console has no new warn/error。

packages/vue-element-cui-nuxt Windows PowerShell build false hang and Nitro trace incident (2026-03)

Problem symptoms

  • pnpm --filter @eams-monorepo/vue-element-cui-nuxt build stays at Building Nuxt Nitro server (preset: node-server)for a long time; after multiple timeout reruns, it looks like "the more it runs, the more stuck it gets, until it is completely stuck".

Actual root cause

  • There are two layers of causes combined. The first layer is the real blocking point: the Nitro node-server packaging stage defaults to externals.trace which triggers nodeFileTrace, and in the current docs site + pnpm workspace + Windows environment, it continuously consumes high CPU and high memory, and the build gets stuck for a long time at the Nitro finishing stage. The second layer is the illusion magnified: under PowerShell, timeout termination, manual interruption, or Start-Process running in the background pnpm -> cmd -> node -> nuxt build when the outer command ends, it does not mean the inner child process tree has exited; the old build chain will remain and overlap with the new build.

Key misleading point

  • The log stopping on the same line does not mean the process is already idling; if you do not first clean up the leftover child processes, subsequent Get-Process, log, and artifact observations will mistake old process noise for the state of the current command.

Key clue

  • When reproducing with a single process,.nuxt/dist/server/server.mjs has already been generated, but .output/server is still empty, indicating that Vite SSR has completed and the stuck point is at the Nitro finishing stage; at the same time, nuxt.mjs build 's working set can rise above 2GB, and CPU still keeps increasing, which matches the characteristics of nitropack 's nodeFileTrace tracing stage.

Effective fix

  • First clean up the old pnpm -> cmd -> node build chain according to command-line characteristics, keeping only one isolated process for reproduction; then explicitly set packages/vue-element-cui-nuxt/nuxt.config.ts in nitro.externals.inline = [/.*/](rather than trace = false), so that Rollup inlines all dependencies into the server bundle, while bypassing the @vercel/nft tracing deadlock issue under Windows + pnpm workspace.

Verification method

  • Run pnpm --filter @eams-monorepo/vue-element-cui-nuxt exec nuxi build --logLevel=verboseas a single process; it should generate .output/server/index.mjs and print Build complete!; at the same time, confirm that the target build process chain is no longer left behind.

Follow-up constraints

  • When reproducing "build deadlock" under Windows PowerShell in the future, first confirm whether old child processes remain, then determine whether the current command is actually stuck; do not directly attribute the phenomenon after multiple leftover build chains overlap to the current change.
  • Do not use nitro.externals.trace = false—although it can bypass the tracing deadlock, it will cause the Vercel cloud function artifact to lack node_modules and package.json, and error directly at runtime (see "Vercel Cloud Function Missing Dependency Incident" below). The correct workaround is externals.inline = [/.*/], so that dependencies are inlined into the bundle rather than relying on external node_modules。

packages/vue-element-cui-nuxt 's Vercel cloud function entities/decode crash incident (multi-version dependencies + Nitro externals chain of pitfalls, 2026-04)

Problem symptoms

  • After the docs site is deployed to Vercel, all requests return 500 FUNCTION_INVOCATION_FAILED, and the runtime logs uniformly report Cannot find module 'entities/decode', with the require stack pointing to /var/task/node_modules/@vue/compiler-core/dist/compiler-core.cjs.prod.js。

Actual root cause (two layers stacked)

  • First layer (initial trigger):nuxt.config.ts in nitro.externals.trace = false disabled @vercel/nft(Node File Trace), causing the build artifact __fallback.func/ to completely contain no node_modules and package.json, and the cloud function cannot find any external dependencies at runtime.
  • Second layer (the real root cause)There are three different versions of entities(4.5.0 via svgo、6.0.1 via parse5、7.0.1 via @vue/compiler-core@3.5.30)。@vue/compiler-core 's CJS production build performing require('entities/decode')at runtime, requiring entities@7.x 's ./decode subpath export. When Nitro's @vercel/nft traces dependencies, it may trace the wrong version (4.x or 6.x), or when Vercel installs dependencies from the function's package.json , it may pull the wrong version, causing entities/decode unavailable at runtime.

Key misleading points and pitfalls

  • Misleading point 1: Initially thought that simply removing trace: false would fix it. But even after removal, when Vercel builds on Linux, Nitro's default trace still did not correctly include entities@7.x(because multiple versions coexist, the trace may select the wrong version).
  • Misleading point 2: Switching to externals.inline = [/.*/] could generate a self-contained bundle when building locally on Windows ("dependencies": {}), and it looked fixed. But the Vercel build framework, after Nitro, wouldrun its own @vercel/nftagain, and after detecting residual require() references in the bundle, recopied an incomplete Vue runtime from the project node_modules (missing the correct version of entities), causing the same runtime error.
  • Misleading point 3: Assuming that "correct local build artifacts = correct Vercel deployment." In reality, Vercel rebuilds on its own Linux server, and the pnpm workspace's node_modules structure is different, turbo cache behavior is different, and@vercel/nft tracing results are also different.Local acceptance cannot replace actual Vercel deployment verification.

Effective fix (two-step combination)

  • (1) Remove all nuxt.config.ts in nitro.externals configuration, letting Nitro use the default @vercel/nft trace behavior (Vercel builds on Linux, so the Windows trace hang issue does not exist).
  • (2) Add entities as an explicit packages/vue-element-cui-nuxt/package.json of dependencies("entities": "^7.0.1"), and in pnpm-workspace.yaml of overrides add entities: "^7.0.1", forcing the entire workspace to use a unified 7.x version and eliminating multi-version ambiguity.

Verification method

  • After Vercel deploys commit 211c662 ,https://vec.ruan-cat.com/ no longer returns FUNCTION_INVOCATION_FAILED, but instead returns a Nuxt application-layer JSON error response ({"statusCode": 500, "statusMessage": "Server Error"}) - proving that the cloud function has started normally and theentities/decode module is available; the Nuxt Content API (such as /api/_content/query) correctly responds with 404 (content not found) instead of crashing due to a missing module.

Subsequent constraints

  • Never use nitro.externals.trace = false. It causes cloud functions on serverless platforms such as Vercel/Netlify to fail to find dependencies at runtime.
  • Do not use nitro.externals.inline = [/.*/] to fix Vercel deployments. It works locally, but the Vercel build framework will run @vercel/nftagain after Nitro, reintroducing an incomplete node_modules。
  • When a dependency tree has multiple versions, you must use pnpm-workspace.yaml the overrides to unify and lock it, especially for packages depended on by runtime CJS require() subpath exports (such as entities)。
  • Vercel deployment issues cannot be verified only locally. Local builds and Vercel builds may differ in trace results,node_modules structure, and cache behavior, so you must confirm the runtime state through Vercel MCP or by directly accessing the deployment URL.
  • When troubleshooting Vercel deployment failures, the first checkpoint iserror type:FUNCTION_INVOCATION_FAILED(module missing/function crash) vs Nuxt JSON error response (application-layer SSR error); the troubleshooting paths for the two are completely different.

Vercel cloud function @vueuse/core Module missing incident — workspace package + Vite SSR externalization chain of pitfalls (2026-04)

Symptom

  • After the docs site was deployed to Vercel, at runtime it threw ERR_MODULE_NOT_FOUND: Cannot find package '@vueuse/core' imported from /var/task/node_modules/element-plus/es/hooks/use-calc-input-width/index.mjs, and the cloud function crashed and returned 500.

Actual root causes (three layers stacked)

  • First layer (Vite SSR externalization): by default, the Vite SSR build marks packages in node_modules as external, including workspace packages @eams-monorepo/vue-element-cui and element-plus. This means that at runtime they need to be loaded from node_modules .
  • Second layer (workspace package import chain):@eams-monorepo/vue-element-cui(introduced via workspace:* ) compiled output dist/index.js contains import ... from 'element-plus',element-plus ESM files that in turn import ... from '@vueuse/core'. Complete chain: Nuxt SSR → workspace package (external) → element-plus (external) → @vueuse/core (missing).
  • Third layer (pnpm multiple versions + NFT trace failure):@vueuse/core has 3 versions in the workspace (v12/v13/v14), and pnpm's symlink structure causes @vercel/nft to fail to trace the correct version, so@vueuse/core is not included in the cloud function's node_modules .

Key misleading points and the path of pitfalls

  • Misleading point 1: assuming nitro.externals.inline can solve the problem. In fact, Nitro's inline acts at the Nitro Rollup stage, but Vite SSR has already externalized these packages at an earlier stage; what Nitro receives is already-externalized import statements, and the inline configuration has no chance to intervene.
  • Misleading point 2: assuming that simply adding @vueuse/core as a direct dependency would be enough. But there are 3 major versions (v12/v13/v14), and overriding to a single version may break compatibility (element-plus needs v12, shadcn-docs-nuxt needs v14).
  • Misleading point 3: ignoring the special nature of workspace packages in SSR. Workspace packages exist in node_modulesvia symlinks, and Vite externalizes them by default. Their internal imports of element-plus are resolved at runtime from the workspace package's directory context, not from the Nuxt app's directory.

Effective fix

  • In nuxt.config.ts 's vite.ssr.noExternal , list the workspace packages and element-plus 's complete runtime dependency tree to prevent Vite SSR from externalizing them and force them into the server bundle at build time:
    vite: {
      ssr: {
        noExternal: [
          "@eams-monorepo/vue-element-cui", // workspace 包
          /element-plus/, /@element-plus/, /@vueuse/, /vue-demi/,
          /@ctrl\/tinycolor/, /@floating-ui/, /@popperjs\/core/,
          /async-validator/, /escape-html/, /lodash-unified/, /lodash-es/,
          /memoize-one/, /normalize-wheel-es/, /entities/,
        ],
      },
    }
    
  • At the same time, combine with isWindows(from std-env) to conditionally skip NFT trace during local builds on Windows (to avoid hanging); Vercel Linux builds trace normally.

Verification method

  • Local build: confirm that element-plus code appears in __fallback.func/chunks/ 's server chunks (rather than node_modules), and the bundle size grows from 5.87 MB to 8.38 MB.
  • Vercel deployment:https://vec.ruan-cat.com/ returns HTTP 200 (rather than the previous 500 crash),/api/_content/navigation responds normally (no longer reporting ERR_MODULE_NOT_FOUND)。

Subsequent constraints

  • When solving Vercel SSR missing-dependency issues, check vite.ssr.noExternalfirst, rather than nitro.externals.inline. The two act at different stages (Vite SSR build vs Nitro Rollup), and the former is the fundamental fix point.
  • Workspace packages (workspace:*) must be added to noExternalin SSR scenarios; otherwise loading via symlinks at runtime will lose the dependency context.
  • When adding noExternal entries, you must list the target package'scomplete runtime dependency tree(such as element-plus → @vueuse/core → @vueuse/shared); omitting any single transitive dependency may cause new ERR_MODULE_NOT_FOUND。
  • When using std-env and other non-Node.js built-in packages, you must explicitly declare them in the current subpackage's package.json to avoid phantom dependencies.

Complete production failure of the Nuxt Content documentation site—a Windows local build patch triggered a cascading collapse of Vercel Linux deployment (2026-04 full postmortem)

Scope:packages/vue-element-cui-nuxt(component library documentation site) Time:2026-04 Keywords: pnpm monorepo, Vercel serverless, Nitro, Vite SSR, @vercel/nft, prerendering, document-driven, workspace packages, multi-version dependencies

Full Picture of the Incident

This is acascading collapse triggered by a Windows local build optimization and exposed in the Vercel Linux production environment. The @vercel/nft added initially to address Windows local nitro.externals.trace = false trace hangs and the prerender:routes clearing hook continued to affect Vercel deployments over the following months, ultimately leading to a three-layer compounded failure:

Layer Symptom Root Cause
First layer FUNCTION_INVOCATION_FAILED,Cannot find module 'entities/decode' trace: false caused the cloud function to be missing node_modules; subsequent entities multi-version ambiguity
Second layer ERR_MODULE_NOT_FOUND: Cannot find package '@vueuse/core' element-plus was externalized by Vite SSR; the workspace package import chain + pnpm symlinks caused NFT tracing to fail
Third layer TypeError: Cannot read properties of null (reading '_id') prerender:routes clearing hook disabled prerendering; document-driven Nuxt Content could not parse markdown into structured objects at build time, and the runtime content database was empty

Core Lessons

Do not use a patch that "works locally" to solve production environment problems. Windows and Linux have completely different node_modules structures,@vercel/nft behavior, and prerendering processes. Every workaround added for Windows may create new problems on Linux:

Windows Patch Local Problem Solved Production Problem Caused
nitro.externals.trace = false NFT trace hangs Cloud function completely missing node_modules
nitro.externals.inline = [/.*/] Bypass trace hangs Vercel's secondary NFT tracing introduced incomplete node_modules
prerender: { crawlLinks: false } + routes.clear() Reduce build time Content documents were not pre-parsed, and the runtime database was empty

Final Fix Plan (all used together)

  1. vite.ssr.noExternal: Add the workspace package @eams-monorepo/vue-element-cui and element-plus complete dependency tree to noExternal, preventing Vite SSR externalization and bundling them into the server bundle at build time.
  2. nitro.externals.inline: Keep a precise inline list as a supplement (mutually insuring with ssr.noExternal ).
  3. isWindows ? { trace: false } : {}: Use std-env to detect the platform; skip NFT trace only for Windows local, and perform normal trace on Vercel Linux.
  4. prerender: { crawlLinks: true }: Restore prerendering so that document-driven Nuxt Content parses markdown into structured objects at build time.
  5. pnpm-workspace.yaml overrides: Lock entities: "^7.0.1" to eliminate multi-version ambiguity.
  6. Explicit Dependency Declaration:entities、std-env and other packages are explicitly added to the subpackage package.json, eliminating phantom dependencies.

Subsequent Constraints

  • Always verify with an actual deployment on Vercel first, and do not use local build results as the final criterion.
  • Unconditionally using trace: false or inline: [/.*/]is prohibited; it must be made conditional based on platform detection.
  • Do not clear prerendered routes(routes.clear()); document-driven Nuxt Content depends on parsing content during the prerender phase.
  • Workspace packages must be added in SSR scenarios to vite.ssr.noExternal。
  • When fixing Windows build issues, the impact on the Linux production environment must also be evaluated—the pnpm symlink structure, NFT tracing behavior, and prerendering process all differ between the two platforms.

PowerShell Git Batch Merge Script Incident

Scope:eams-frontend-monorepo/scripts Time:2026-03 Keywords: UTF-8 BOM, pipeline misuse, git hooks,stderr、$LASTEXITCODE、--no-ff

Symptoms

False syntax errors

  • A .ps1 containing Chinese reports under Windows PowerShell 5 errors such as "The string is missing the terminator" and "Unexpected token }", etc.; this is actually an encoding parsing issue, not a logic error.

False "conflict" reports and merge --abort failures

  • git merge origin/f1 actually succeeded, but the script entered catchand reported "conflict or failure".
  • The message is mixed with hook output, such as ℹ 输出 N 个暂存区文件路径, ANSI color codes.
  • Subsequently executing git merge --abort reports fatal: There is no merge to abort, because MERGE_HEAD no longer exists.

Misunderstanding of push cadence

  • Mistakenly believed that "the merge succeeded but was not pushed to the remote"; this needs to be aligned with the product: a single push at each step push。

Abnormal bloat of the history graph

  • The batch merge script used git merge --no-fffor a long time; even when fast-forwarding was possible, it forcibly added merge nodes.
  • The result was that the branch graph showed a large number of extra merge commits, making it harder to read and trace, and obscuring the real conflict points.

Actual Root Causes

Encoding and PS5

  • UTF-8 without BOM is read by PS5 according to the system code page, and the Chinese bytes break the closing quotation marks.

$ErrorActionPreference, pipelines and hooks stderr

  • At the top of the script $ErrorActionPreference = "Stop" and git merge ... 2>&1 | ForEach-Object { ... } are used together.
  • After the merge completes, post-merge and other hooks may still write information to stderr .
  • After the pipeline merges stderr in, PowerShell easily treats the native stderr as aterminating error, and directly enters catch; at this point the merge has already ended,MERGE_HEAD has been cleared, andmerge --abort has no merge to abort.

Pipelines and exit codes

  • $LASTEXITCODE after a pipeline cannot reliably represent git merge itself, for the same reason as git push .

Improper merge strategy configuration

  • Enabled by default in batch synchronization scenarios, --no-ff, which is strategy abuse.
  • This configuration turns "preserve explicit merge nodes" from an exception into the norm, resulting in excessively noisy commit graphs.

Key Misleading Points

  • Treating the text in catch as a real merge conflict.
  • Treating the fatal from merge --abort as repository corruption.
  • First check whether MERGE_HEAD exists, whether a merge commit has already been produced; if the merge has already succeeded, it is mostly a false positive.

Effective fix

Script encoding

  • Save as UTF-8 with BOM; if the BOM is lost after saving in the editor, it needs to be written again.

How git is invoked

  • Do notwrap git merge / git push。
  • Execute git ...directly, then use if ($LASTEXITCODE -ne 0) to determine success or failure.

Remote update cadence

  • If remote every step visibility is required: in merge-all-branches-to-f1.ps1 ineach timeafter a successful merge, execute git push origin f1。
  • and merge-f1-to-all-branches.ps1align with the strategy of "push immediately after each sub-branch merge".

Merge strategy reverts to default

  • Remove --no-fffrom the script, restore git merge --no-edit default behavior.
  • Let Git fast-forward directly when possible, and only produce a merge node when there is an actual divergence.

Verification method

  • Parser::ParseFile has no syntax errors for .ps1 .
  • Actually run it through: successfully merged branches can normally git push。
  • "merge succeeded but abort is executed" no longer occurs.
  • On the sub-branch, git status has no unexpected conflict state.

Subsequent constraints

Encoding and git invocation

  • This repository's PowerShell + git automation defaults to UTF-8 BOM。
  • forbiddento use git merge / git push with 2>&1 | pipe; consistent with the "push without pipe" comment in the script.
  • When troubleshooting, if you see hook-related stderr text, first suspect Stop + pipe, rather than a real merge failure.
  • The batch sync script uses normal merge behavior by default,abuse of --no-ffis forbidden; if the business explicitly requires "never add a merge node", it should be changed to --ff-only and accept abort on failure.

Where the experience lands

  • When adding similar explanationsdo notin .cursor/skills create a separate parallel SKILL; instead merge the incident patterninto this skill's repository-level experience library.

packages/vue-element-cui CuiDialog overlay completely failing incident (Element Plus appendToBody default value change + CSS stacking context, 2026-04)

Problem symptoms

  • On the documentation site (reproduced in both dev and production environments), after clicking the "Open confirmation overlay" button, the dialog pops up butthere is no semi-transparent overlay covering the page—the header, sidebar, and body content behind it are all clearly visible and clickable; the dialog merely floats above the page, and the visual hierarchy is completely disordered.

Actual root cause (two layers stacked)

  • First layer (Teleport disabled): Element Plus 2.13.x changed the dialog's appendToBody property type to Boolean(no explicit default value); in Vue 3, when a Boolean prop is not passed it defaults to false. In the source code, ElTeleport 's disabled evaluates to !appendToBody, i.e. !false = true, causing <Teleport to="body"> to be disabled. The overlay is no longer mounted to <body>, but remains in the DOM level where the component is located.
  • Second layer (CSS stacking context traps the overlay): the documentation site's demo container .cui-demo-container is set with isolation: isolate(for style isolation), creating a new stacking context. Although the overlay is position: fixed and z-index: 2002, its z-index only takes effect within .cui-demo-container 's stacking context, and cannot cover elements such as the header (z-index: 40)、sidebar(z-index: 30) in the upper layers of the page.

Key misleading points

  • Misleading point 1: At first, it was suspected that nuxt.config.ts in vite.ssr.noExternal 's overly aggressive dependency externalization configuration caused the CSS to be lost. After actually checking the production CSS file (367KB), it was confirmed that all Element Plus style classes (.el-dialog、.el-overlay、.el-button), CSS variables (--el-color-primary、--el-overlay-color-lighter) exist and are complete.
  • Misleading point 2: It was suspected that Tailwind CSS v4's @layer base preflight reset overrode Element Plus styles. In fact, Element Plus CSS is unlayered styles, which always take precedence over rules in @layer base in the CSS cascade.
  • Misleading point 3: When inspecting the overlay via getComputedStyle , all properties look completely correct (background-color: rgba(0,0,0,0.5)、position: fixed、inset: 0px、z-index: 2002), but visually there is no mask effect on the page.Key turning pointwas checking overlay.parentElement and finding that its parent node is DIV.space-y-4(inside the demo component) rather than BODY, then tracing the ancestor chain to find isolation: isolate。

Effective fix

  • In the CuiDialog component's <el-dialog> , add the append-to-body attribute to force-enable Teleport to mount the overlay to the <body> level, bypassing .cui-demo-container 's stacking context limitation.

Verification method

  • document.querySelector('.el-overlay').parentElement === document.body returns true, confirming that the overlay has been mounted to body.
  • document.elementFromPoint() At various positions on the page (header, sidebar, content, corner), all return el-overlay-dialog, confirming that the mask covers the entire page.
  • All 292 component library tests pass, with no regressions.

Subsequent constraints

  • After upgrading Element Plus, the Teleport behavior of popup components must be checked. Element Plus's appendToBody/teleported default values change between major versions (old version teleported defaults to true, new version appendToBody defaults to false). After upgrading, if the popup does not show a mask, check this item first.
  • When using isolation: isolate to create a stacking context, you must also ensure that the internal popup component has Teleport enabled, otherwise the overlay's z-index will be trapped within that context.
  • When troubleshooting "overlay styles are correct but visually ineffective", the first checkpoint is whether overlay.parentElement is body, not checking CSS property values. The most common reason an overlay is invisible even though all CSS properties are correct is failed Teleport + stacking context.

Additional information that must be retained when writing the experience

If this bug is similar to an existing incident pattern in the repository, do not omit the following additional information when writing the memory:

  • Whether this issue broke a baseline that a "user has confirmed as stable"
  • Whether there is a "do not change arbitrarily" configuration, for example extends: ["shadcn-docs-nuxt"]
  • Where does the first trustworthy signal come from: terminal logs, browser console, network requests, or build output
  • Which category does this fix belong to: build configuration fallback, dependency entry compatibility, template-layer override, style-layer completion, or startup pre-preparation
  • Is there a highly misleading illusion this time, for example "looks like a style issue, but is actually hydration"
  • Is the final verification based on a fresh process, fresh logs, and fresh page rather than historical cache

How to write verification evidence

When writing incident records in the future, prioritize recording evidence that can be repeatedly verified, rather than vague wording.

Recommended evidence wording

  • fresh dev.stderr 为空
  • /components Returns 200
  • Chrome console No new warn/error
  • Dark mode toggle restored, sidebar collapse restored

Not recommended vague wording

  • "It should be fine now"
  • "It looks like it's fixed"

What not to write

Absorbing root-level AI memory experience into the skill does not mean writing the skill as a repair manual. The following content should not become the main body of this skill:

  • Long command execution logs
  • Generalized debug theory unrelated to the current repository
  • Listing every trial-and-error process one by one
  • Packaging a one-time temporary workaround as a permanent rule
  • Using "these commands must be executed" instead of "which conclusions should be recorded"

Recording process

  1. First confirm that the bug is clearly understood and the fix is complete.
  2. Compress the result into 4 to 6 high-signal facts.
  3. Choose the right memory destination.
  4. If it is repository-level experience, update the root-level AI memory document.
  5. Update Memorix with the same conclusions, and choose the right memory type.
  6. Read the text back once and delete transient noise, guesses, and low-value command history.
  7. If the user also asks to commit, hand off the commit action to a separate git workflow.

Characteristics of good memory

  • Explain clearly "why it broke", rather than only writing what commands were run
  • Clearly identify the first trustworthy clue and explain how it broke the wrong assumption
  • Describe the final fix in a reusable way
  • Write verification actions that future agents can repeat
  • Make the next troubleshooting session noticeably shorter

Common mistakes

  • Starting to write speculative conclusions before the root cause is confirmed
  • Writing a very long debug diary instead of reusable conclusions
  • Writing repository-level experience in the wrong place
  • Failing to write out the wrong assumptions that caused the detour
  • Mixing fix instructions and memory distillation together
  • Forgetting to sync local MCP memory

Boundary

This skill is only responsible for memory distillation and summarization.

It cannot replace debugging, implementation, testing, and repair workflows. If the bug is not fixed yet, first use the appropriate debugging or implementation skill, and return to this skill for experience distillation after the result is stable.


Additional error-prone point: integration changes must not delete or reduce original comments and component description information

Problem symptoms

  • To integrate a new tool or adjust the initialization order, directly rewriting the entry file or component file in full, causing the original comments, explanatory text, naming semantics, and information conveyed by the component to be erased along with it.

Actual root cause

  • Mistaking "feature integration" for "permission to overwrite the original file's expression layer," focusing only on whether the code still runs, and not treating comments, explanatory copy, and structural naming as part of the existing implementation.

Key misleading points

  • On the surface, it is merely restoring the import order, plugin order, or template structure, so it is easy to mistakenly assume that "if the logic is equivalent, there is no problem"; but for this repository, the original comments and component descriptions are themselves conventions and context, not noise that can be discarded at will.

Effective fix

  • Prioritize minimal patch-style changes, preserving the original comments, original explanatory text, and original component expression; if an entire section must be rewritten, first reread the baseline file, migrate the original comments and explanatory information back together, and then add the new integration notes.

Verification method

  • Compare the target file before and after modification to confirm that the original comment blocks, original explanatory text, and original component semantics are still present; do not verify only that it runs, but also verify that the information expression has not been reduced.

Follow-up constraints

  • Subsequently, in main.ts, sample pages, component READMEs, and component entry files, when integrating tools or adjusting structure, do not use overwrite-style rewriting instead of local modification; do not delete comments, and do not erode the information originally conveyed by the component.

Misuse of phantom dependencies in a pnpm monorepo (2026-04)

Problem symptoms

  • In packages/vue-element-cui-nuxt/nuxt.config.ts directly import { isWindows } from "std-env", but packages/vue-element-cui-nuxt/package.json did not declare std-env as a dependency. Locally, because .npmrc 's shamefully-hoist=true hoisted std-env(a transitive dependency of Nuxt) to the root node_modules, the code could resolve normally, but this is a typical phantom dependency.

Actual root cause

  • When AI replaced import { platform } from "node:os" with std-env , it only confirmed that "the Nuxt ecosystem already has std-envbuilt in" and used it directly, without checking whether the current package.json explicitly declared that dependency. Under pnpm strict mode or other package managers, this kind of phantom dependency will directly cause ERR_MODULE_NOT_FOUND。

Key misleading points

  • "Nuxt/Nitro already has the dependency built in" easily leads people to think they can import it directly, ignoring pnpm's dependency isolation mechanism.shamefully-hoist=true masks the phantom dependency problem, local development works fine, but deployment or other environments may fail.

Effective fix

  • In packages/vue-element-cui-nuxt/package.json 's dependencies , explicitly add "std-env": "^3.10.0"。

Verification method

  • pnpm why std-env confirm that the dependency chain is correct; check package.json to confirm that the explicit declaration exists.

Follow-up constraints

  • When importing third-party packages in any subpackage of a pnpm monorepo,you must first confirm that the package has already been declared explicitly in the current subpackage's package.json explicitly declared in, regardless of whether it is installed indirectly by an upper-level dependency. Even for known internal dependencies of frameworks such as Nuxt, Nitro, and Vite (such as std-env、pathe、defu、consola , etc.), you must not skip the explicit declaration and use them directly.
  • If the functionality can be implemented with Node.js built-in modules (such as node:os、node:path), prioritize using the built-in modules to avoid introducing unnecessary external dependencies.