{"record":{"id":"8feb0faab1e253b1","repo":"withastro/astro","slug":"expected-server-export-in-actions-file-to-be-an","errorCode":null,"errorMessage":"Expected `server` export in actions file to be an object. Received ${typeof server}.","messagePattern":"Expected `server` export in actions file to be an object\\. Received (.+?)\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/astro/src/actions/load.ts","lineNumber":36,"sourceCode":"\n/**\n * Clears the cached actions so they are re-resolved on the next request.\n * Called via HMR when action files change during development.\n */\nexport function clearActions(manifest: SSRManifest): void {\n\tactionsMemo.invalidate(manifest);\n}\n\n/** Looks up a single action handler by its dot-separated path. */\nexport async function getAction(\n\tmanifest: SSRManifest,\n\tpath: string,\n): Promise<ActionClient<unknown, ActionAccept, $ZodType>> {\n\tconst pathKeys = path.split('.').map((key) => decodeURIComponent(key));\n\tlet { server } = await getActions(manifest);\n\n\tif (!server || !(typeof server === 'object')) {\n\t\tthrow new TypeError(\n\t\t\t`Expected \\`server\\` export in actions file to be an object. Received ${typeof server}.`,\n\t\t);\n\t}\n\n\tfor (const key of pathKeys) {\n\t\t// An action is a leaf: once resolved to a function, its own properties\n\t\t// are not part of the action namespace and cannot be traversed further.\n\t\tif (typeof server === 'function') {\n\t\t\tthrow new AstroError({\n\t\t\t\t...ActionNotFoundError,\n\t\t\t\tmessage: ActionNotFoundError.message(pathKeys.join('.')),\n\t\t\t});\n\t\t}\n\t\tif (FORBIDDEN_PATH_KEYS.has(key)) {\n\t\t\tthrow new AstroError({\n\t\t\t\t...ActionNotFoundError,\n\t\t\t\tmessage: ActionNotFoundError.message(pathKeys.join('.')),\n\t\t\t});","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/withastro/astro/blob/52e6c34790cc8ac4e69e6135ace06049867e5c4a/packages/astro/src/actions/load.ts#L18-L54","documentation":"When resolving an action, Astro loads the server-side actions module from the manifest and expects its `server` export to be a plain object that forms the action namespace. If that export is missing, falsy, or not an object (a function, string, etc.), action lookup cannot proceed and this TypeError is thrown at load time.","triggerScenarios":"src/actions/index.ts exporting `server` as a non-object (e.g. `export const server = someFunction`), exporting a default instead of the expected shape, or the built/virtual astro:actions module resolving to garbage after a broken build or interrupted HMR update. Any getAction() call — RPC POST or server-side callAction — hits this first.","commonSituations":"Upgrading between Astro versions where the expected actions-file export shape changed (server object vs named exports); hand-editing the actions index after scaffolding; a stale dist/ or node_modules/.vite cache serving a malformed virtual module.","solutions":["Open src/actions/index.ts and verify it exports actions correctly — either named `defineAction()` exports or an object under `server` — matching your Astro version's docs","Restart the dev server (or clear node_modules/.vite and rebuild) so the astro:actions virtual module regenerates","If you import astro:actions/server.js directly somewhere, stop — use the documented `astro:actions` entry so the bundler resolves the right module","Check for a build error earlier in the log: a failed actions-file compile can surface here as a bad server export"],"exampleFix":"// before — src/actions/index.ts\nexport const server = () => defineAction({ /* ... */ }); // function, not an object\n\n// after\nimport { defineAction } from 'astro:actions';\nexport const server = {\n  getGame: defineAction({\n    input: z.object({ id: z.string() }),\n    handler: (input) => ({ id: input.id }),\n  }),\n};","handlingStrategy":"validation","validationCode":"// in dev-only bootstrap code, assert the shape before first use\nimport * as actionsModule from './actions/index.js';\nconst server = (actionsModule as any).server ?? actionsModule;\nif (typeof server !== 'object' || server === null) {\n  throw new Error('actions/index.ts must export the actions namespace as an object');\n}","typeGuard":"function isValidActionsServer(v: unknown): v is Record<string, unknown> {\n  return typeof v === 'object' && v !== null && !Array.isArray(v);\n}","tryCatchPattern":"try {\n  const action = await getAction(manifest, 'blog.like');\n} catch (e) {\n  if (e instanceof TypeError && e.message.includes('`server` export')) {\n    // fix actions/index.ts exports, then restart dev server\n  } else throw e;\n}","preventionTips":["Keep src/actions/index.ts minimal: only defineAction exports and nested namespaces","Run astro check / typecheck so a malformed actions file fails in CI, not at runtime","Restart the dev server after restructuring the actions file so the virtual module regenerates"],"tags":["astro-actions","typeerror","module-export","virtual-module"],"backgroundTag":"invalid-module-export-shape","analyzedSha":"52e6c34790cc8ac4e69e6135ace06049867e5c4a","analyzedAt":"2026-08-18T18:48:03.901Z","contentChangedAt":"2026-08-18T18:48:03.901Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}