{"record":{"id":"d291dbc966b5d7c5","repo":"denoland/deno","slug":"invalid-registry-configuration-url-for-vari-d291db","errorCode":null,"errorMessage":"Invalid registry configuration. Url \"{}\" (for variable \"{}\" in registry with schema \"{}\") uses variable \"{}\", which is not allowed because the schema defines \"{}\" to the right of \"{}\".","messagePattern":"Invalid registry configuration\\. Url \"(.+?)\" \\(for variable \"(.+?)\" in registry with schema \"(.+?)\"\\) uses variable \"(.+?)\", which is not allowed because the schema defines \"(.+?)\" to the right of \"(.+?)\"\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/lsp/registries.rs","lineNumber":370,"sourceCode":"      let key_index = key_index.ok_or_else(||anyhow!(\"Invalid registry configuration. Registry with schema \\\"{}\\\" is missing a path parameter in schema for variable \\\"{}\\\".\", registry.schema, variable.key))?;\n\n      let replacement_variables = parse_replacement_variables(&variable.url);\n      let limited_keys = key_names.get(0..key_index).unwrap();\n      for v in replacement_variables {\n        if variable.key == v && config.version == 1 {\n          return Err(anyhow!(\n            \"Invalid registry configuration. Url \\\"{}\\\" (for variable \\\"{}\\\" in registry with schema \\\"{}\\\") uses variable \\\"{}\\\", which is not allowed because that would be a self reference.\",\n            variable.url,\n            variable.key,\n            registry.schema,\n            v\n          ));\n        }\n\n        let key_index = limited_keys.iter().position(|key| key == &v);\n\n        if key_index.is_none() && variable.key != v {\n          return Err(anyhow!(\n            \"Invalid registry configuration. Url \\\"{}\\\" (for variable \\\"{}\\\" in registry with schema \\\"{}\\\") uses variable \\\"{}\\\", which is not allowed because the schema defines \\\"{}\\\" to the right of \\\"{}\\\".\",\n            variable.url,\n            variable.key,\n            registry.schema,\n            v,\n            v,\n            variable.key\n          ));\n        }\n      }\n    }\n  }\n\n  Ok(())\n}\n\n#[derive(Debug, Clone, Deserialize)]\npub struct RegistryConfigurationVariable {","sourceCodeStart":352,"sourceCodeEnd":388,"githubUrl":"https://github.com/denoland/deno/blob/f7822238cab635a3a19f99f493f675fa81a7f9d8/cli/lsp/registries.rs#L352-L388","documentation":"Registry URL templates in a Deno LSP autocomplete registry configuration may only substitute variables that the schema defines to the LEFT of the variable being resolved. The LSP matches import URLs against the schema left-to-right, so a later variable's value is not yet known when an earlier variable's endpoint is fetched; a forward reference is therefore rejected for both version 1 and 2 configs. The error names the offending URL, the variable being resolved, the schema, and which key is defined too far right.","triggerScenarios":"Any registry (v1 or v2) where a variable's \"url\" substitutes a key positioned after it in the schema — e.g. schema \":module@:version\" with {\"key\": \"module\", \"url\": \"https://example.com/list?version=${version}\"}. Also fired when the URL references a name that is not a schema key at all (it is neither left of the variable nor the variable itself).","commonSituations":"Wrapping an API that needs a later path segment to list earlier ones (listing a module's versions when the schema puts module first); adapting npm-style or Go-module-proxy-style APIs to the Deno registry schema; editing a schema and forgetting the left-to-right ordering rule.","solutions":["Make the earlier variable's URL self-contained: point it at an endpoint that does not need later variables (e.g. a static module list) so the forward reference disappears.","Restructure the schema string so variables that other URLs depend on appear first, and update it to match the import URLs it should capture.","Have the listing endpoint accept only the information available at that stage (serve it from a proxy that fills in the missing piece server-side)."],"exampleFix":"// before (registries.json)\n{\n  \"version\": 2,\n  \"registries\": [\n    {\n      \"schema\": \":module@:version\",\n      \"variables\": [\n        { \"key\": \"module\", \"url\": \"https://api.example.com/modules?for=${version}\" },\n        { \"key\": \"version\", \"url\": \"https://api.example.com/modules/${module}/versions\" }\n      ]\n    }\n  ]\n}\n\n// after\n{\n  \"version\": 2,\n  \"registries\": [\n    {\n      \"schema\": \":module@:version\",\n      \"variables\": [\n        { \"key\": \"module\", \"url\": \"https://api.example.com/modules\" },\n        { \"key\": \"version\", \"url\": \"https://api.example.com/modules/${module}/versions\" }\n      ]\n    }\n  ]\n}","handlingStrategy":"validation","validationCode":"// Reject forward references before the LSP does: a variable's URL may only\n// use variables the schema defines to its LEFT (or itself, in version 2).\nexport function assertNoForwardReferences(config) {\n  for (const registry of config.registries ?? []) {\n    const keys = [...registry.schema.matchAll(/:([A-Za-z0-9_]+)/g)].map((m) => m[1]);\n    for (const v of registry.variables ?? []) {\n      const idx = keys.indexOf(v.key);\n      const refs = [...v.url.matchAll(/\\$\\{([A-Za-z0-9_]+)\\}/g)].map((m) => m[1]);\n      for (const ref of refs) {\n        const refIdx = keys.indexOf(ref);\n        if (refIdx === -1 || (refIdx > idx && ref !== v.key)) {\n          throw new Error(`url for '${v.key}' uses '${ref}', which the schema '${registry.schema}' defines to its right (or not at all)`);\n        }\n      }\n    }\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Order schema variables so anything a URL substitutes appears earlier in the schema string than the variable using it","Prefer static listing endpoints for the leftmost variable instead of parameterized ones","Run the config through a validation script before publishing it at the registry URL"],"tags":["registries","lsp","autocomplete","configuration","validation","url-template"],"backgroundTag":"registry-config-validation","analyzedSha":"f7822238cab635a3a19f99f493f675fa81a7f9d8","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}