{"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}\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(.+?)\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":"error","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/d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca/packages/astro/src/env/validators.ts#L192-L216","documentation":"Astro validates that no variable declared with `access: \"secret\"` in `env.schema` has a name starting with any prefix listed in `vite.envPrefix`. Vite exposes any matching variable to client-side bundles, which would leak the secret to the browser. Astro refuses to build when it detects this overlap.","triggerScenarios":"Configuring `env.schema` with a secret variable (e.g. `DATABASE_URL: env.string({ access: 'secret' })`) while `vite.envPrefix` includes a prefix that the variable name starts with (e.g. `envPrefix: ['DATABASE']`, or the default that admits names beginning with the configured prefix).","commonSituations":"Copying a secret name that happens to share a prefix with a public variable group; setting a broad `envPrefix` like `['APP_']` and later adding `APP_SECRET_KEY` as a secret; migrating from raw `import.meta.env` to `env.schema` without revisiting `envPrefix`.","solutions":["Rename the secret variable so its name does not start with any string in `vite.envPrefix` (most reliable).","Narrow `vite.envPrefix` to only the prefixes you truly intend to expose client-side, excluding the secret's prefix.","If the variable must be public, change its `access` from `'secret'` to `'public'` — but only if it genuinely is non-sensitive.","Audit the full schema and envPrefix together so no current or future secret name collides."],"exampleFix":"// before\nexport default defineConfig({\n  vite: { envPrefix: ['API_'] },\n  env: { schema: { API_KEY: env.string({ access: 'secret' }) } }\n})\n\n// after: rename the secret so it no longer matches the public prefix\nexport default defineConfig({\n  vite: { envPrefix: ['API_'] },\n  env: { schema: { SECRET_API_KEY: env.string({ access: 'secret' }) } }\n})","handlingStrategy":"validation","validationCode":"function findSecretPrefixConflicts(schema, envPrefix) {\n  const prefixes = Array.isArray(envPrefix) ? envPrefix : [envPrefix];\n  return Object.entries(schema)\n    .filter(([k, o]) => o.access === 'secret' && prefixes.some(p => k.startsWith(p)))\n    .map(([k]) => k);\n}\n// call before build:\nconst conflicts = findSecretPrefixConflicts(envSchema, config.vite.envPrefix);\nif (conflicts.length) throw new Error('rename secrets: ' + conflicts.join(', '));","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Keep secret variable names in a prefix that is explicitly NOT in vite.envPrefix (e.g. SECRET_).","Review env.schema and vite.envPrefix together in code review.","Add a CI lint that runs the conflict check before deploy."],"tags":["security","env","vite","config","secrets"],"backgroundTag":null,"analyzedSha":"d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca","analyzedAt":"2026-08-12T13:37:29.035Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}