{"record":{"id":"22ac1f38922a63b5","repo":"wekan/wekan","slug":"var-not-exist","errorCode":"var-not-exist","errorMessage":"The environment variable ${name} does not exist","messagePattern":"The environment variable (.+?) does not exist","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"server/models/settings.js","lineNumber":52,"sourceCode":"\n// Security fix (reported by meifukun): invitation codes used to be a 6-digit\n// Math.random() value — a ~900,000 keyspace from a NON-cryptographic RNG, with no\n// effective throttling on the sign-up validation — so an attacker who knew a\n// pending invitee's email could brute-force the code and take the invited account\n// (and its private boards). Generate a cryptographically secure 128-bit code\n// instead, which cannot be guessed regardless of retry rate. (A DDPRateLimiter\n// rule is added in server/models/users.js as defence in depth.)\nfunction generateInvitationCode() {\n  const crypto = require('crypto');\n  return crypto.randomBytes(16).toString('base64url');\n}\n\nfunction getEnvVar(name) {\n  const value = process.env[name];\n  if (value) {\n    return value;\n  }\n  throw new Meteor.Error([\n    'var-not-exist',\n    `The environment variable ${name} does not exist`,\n  ]);\n}\n\nfunction loadOidcConfig(service) {\n  check(service, String);\n  return ServiceConfiguration.configurations.findOneAsync({ service });\n}\n\nasync function sendInvitationEmail(_id, { isNewInvitation = true } = {}) {\n  const icode = await getReactiveCache().getInvitationCode(_id);\n  // #4043: never send an invitation email without a code that will validate at\n  // sign-up (the sign-up lookup requires { code: <string>, valid: true }).\n  // Fail loudly instead of mailing a dead code.\n  if (!isInvitationCodeSendable(icode)) {\n    throw new Meteor.Error(\n      'invitation-code-invalid',","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/wekan/wekan/blob/eb1433158b1804bcf3edaa5cb18f08ae2e04d6c2/server/models/settings.js#L34-L70","documentation":"WeKan's settings model reads optional configuration (e.g. Matomo analytics settings) exclusively from environment variables via getEnvVar. Unlike process.env, which silently returns undefined for a missing key, this helper treats a missing variable as a hard configuration error and throws a Meteor.Error with reason 'var-not-exist'. It is thrown on the server while loading Matomo (or similar) config during settings initialization.","triggerScenarios":"getEnvVar is called by getMatomoConf for each required Matomo variable (e.g. MATOMO_URL, MATOMO_SITE_ID, MATOMO_DO_NOT_TRACK). If any one of them is unset or set to an empty string, the throw fires immediately — empty string is falsy and counts as missing.","commonSituations":"Deploying WeKan with Matomo analytics enabled but forgetting to export MATOMO_URL/MATOMO_SITE_ID in the Docker compose file, systemd unit, or snap environment; renaming a variable in a newer WeKan version while the deployment still uses the old name; a CI/container environment dropping env vars declared in an env_file that does not exist.","solutions":["Set the missing environment variable (named in the message) in your deployment environment (docker run -e, compose environment:, systemd Environment=) before starting WeKan","If you do not use Matomo, remove or unset the Matomo-related toggles so getMatomoConf is not invoked, or provide dummy valid values","Check the WeKan docs/Dockerfile for the current expected variable names — names can change between releases","Verify the variable actually reaches the server process (e.g. print env inside the container) — shell sourcing mistakes often leave it unset"],"exampleFix":"// before (Dockerfile/compose without Matomo vars)\nservices:\n  wekan:\n    image: wekan\n// after\nservices:\n  wekan:\n    image: wekan\n    environment:\n      - MATOMO_URL=https://analytics.example.com\n      - MATOMO_SITE_ID=1\n      - MATOMO_DO_NOT_TRACK=false","handlingStrategy":"validation","validationCode":"function hasEnv(name) {\n  return typeof process.env[name] === 'string' && process.env[name].length > 0;\n}\nif (!hasEnv('MATOMO_URL') || !hasEnv('MATOMO_SITE_ID')) {\n  throw new Error('MATOMO_URL and MATOMO_SITE_ID must be set');\n}","typeGuard":"function isEnvSet(name) {\n  return typeof process.env[name] === 'string' && process.env[name] !== '';\n}","tryCatchPattern":"try {\n  const conf = getMatomoConf();\n} catch (e) {\n  if (e.reason === 'var-not-exist') {\n    console.warn('Missing config env var:', e.message);\n    // fall back to disabled analytics\n  } else throw e;\n}","preventionTips":["Validate all required env vars at process startup with a fail-fast check","Use an .env.example file listing every required variable and a startup validator","Pin variable names to the WeKan release you deploy and re-check them on upgrades","In containers, verify env vars actually reach the process (docker exec env)"],"tags":["meteor","environment-variables","configuration","wekan"],"backgroundTag":"missing-env-var","analyzedSha":"eb1433158b1804bcf3edaa5cb18f08ae2e04d6c2","analyzedAt":"2026-09-01T21:05:02.951Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T01:17:15.007Z"}