{"record":{"id":"e04c66abe5345d5c","repo":"withastro/astro","slug":"envprefixconflictswithsecret","errorCode":"EnvPrefixConflictsWithSecret","errorMessage":"The following environment variables are declared with `access: \"secret\"` in `env.schema`, but their names match a prefix in `vite.envPrefix`, which would expose them in client-side bundles:\n\n${conflicts.map((c) => `- ${c}`).join('\\n')}\n\nEither remove the conflicting prefixes from `vite.envPrefix`, or rename these variables to use a prefix not in `vite.envPrefix`.","messagePattern":"The following environment variables are declared with `access: \"secret\"` in `env\\.schema`, but their names match a prefix in `vite\\.envPrefix`, which would expose them in client-side bundles:\n\n(.+?)`\\)\\.join\\('\\\\n'\\)\\}\n\nEither remove the conflicting prefixes from `vite\\.envPrefix`, or rename these variables to use a prefix not in `vite\\.envPrefix`\\.","errorType":"exception","errorClass":"AstroError","httpStatus":null,"severity":"critical","filePath":"packages/astro/src/env/validators.ts","lineNumber":210,"sourceCode":"\tconst schema = config.env.schema;\n\tconst envPrefix = config.vite?.envPrefix;\n\n\t// No schema or using default prefix — nothing to validate\n\tif (Object.keys(schema).length === 0 || !envPrefix) {\n\t\treturn;\n\t}\n\n\tconst prefixes = Array.isArray(envPrefix) ? envPrefix : [envPrefix];\n\tconst conflicts: string[] = [];\n\n\tfor (const [key, options] of Object.entries(schema)) {\n\t\tif (options.access === 'secret' && prefixes.some((prefix) => key.startsWith(prefix))) {\n\t\t\tconflicts.push(key);\n\t\t}\n\t}\n\n\tif (conflicts.length > 0) {\n\t\tthrow new AstroError({\n\t\t\t...AstroErrorData.EnvPrefixConflictsWithSecret,\n\t\t\tmessage: AstroErrorData.EnvPrefixConflictsWithSecret.message(conflicts),\n\t\t});\n\t}\n}\n","sourceCodeStart":192,"sourceCodeEnd":216,"githubUrl":"https://github.com/withastro/astro/blob/52e6c34790cc8ac4e69e6135ace06049867e5c4a/packages/astro/src/env/validators.ts#L192-L216","documentation":"astro:env validates your config before serving or building. This error fires when a variable declared with `access: 'secret'` in `env.schema` has a name matching one of the prefixes listed in `vite.envPrefix`. Vite exposes matching variables on `import.meta.env` in client bundles, so the collision would inline a secret into shipped JavaScript. The message lists every conflicting variable name.","triggerScenarios":"Setting `vite.envPrefix: ['SECRET_']` (or any prefix that matches a secret's name) while env.schema declares e.g. SECRET_API_KEY with access 'secret'; using an empty-string prefix `''`, which matches every variable name, in a project that declares any secret.","commonSituations":"Adopting astro:env while keeping legacy import.meta.env.SECRET_* usage via a broad envPrefix; copy-pasting Vite envPrefix configuration into an Astro project that also uses env.schema; enabling a wide prefix for convenience without checking the schema for secrets.","solutions":["Rename the secret variables so they no longer start with any vite.envPrefix prefix.","Remove the conflicting prefixes from vite.envPrefix and read those values through `astro:env/server` instead of import.meta.env.","If a variable genuinely must reach the browser it is not a secret - declare it `access: 'public'` in env.schema."],"exampleFix":"// before - astro.config.mjs\nexport default defineConfig({\n  vite: { envPrefix: ['SECRET_'] },\n  env: { schema: { SECRET_API_KEY: envField.string({ access: 'secret' }) } },\n});\n\n// after\nexport default defineConfig({\n  env: { schema: { SECRET_API_KEY: envField.string({ access: 'secret' }) } },\n});\n// read server-side: import { SECRET_API_KEY } from 'astro:env/server';","handlingStrategy":"validation","validationCode":"// keep vite.envPrefix and env.schema disjoint for secrets\n// env.schema keys with access 'secret' must not start with any envPrefix entry\nconst envPrefix = ['PUBLIC_'];\nconst schema = { SECRET_API_KEY: 'secret', PUBLIC_SITE_URL: 'public' };\nconst conflicts = Object.entries(schema)\n  .filter(([k, access]) => access === 'secret' && envPrefix.some((p) => k.startsWith(p)))\n  .map(([k]) => k);\nif (conflicts.length) throw new Error('secret/prefix conflicts: ' + conflicts.join(', '));","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Prefer astro:env (env.schema + astro:env/server) over import.meta.env for secrets.","Keep vite.envPrefix narrow; never use an empty-string prefix in a project that declares secrets.","Rely on the config-time throw: run `astro sync` or `astro build` in CI so a collision fails before deploy."],"tags":["environment-variables","security","vite","config"],"backgroundTag":"secret-leak-config-conflict","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"}