{"record":{"id":"271300e97252e748","repo":"theonedev/onedev","slug":"unable-to-find-svg-sprite-resource-mounted-at-m","errorCode":null,"errorMessage":"Unable to find svg sprite resource mounted at: ${mountPath}","messagePattern":"Unable to find svg sprite resource mounted at: (.+?)","errorType":"exception","errorClass":"ExplicitException","httpStatus":null,"severity":"error","filePath":"server-core/src/main/java/io/onedev/server/web/component/svg/SpriteImage.java","lineNumber":99,"sourceCode":"\t\t\tif (mountPath.length() != 0) {\n\t\t\t\tscope = spriteScopes.get(mountPath);\n\t\t\t\tif (scope == null) {\n\t\t\t\t\tList<BaseResourceMapper> resourceMappers = new ArrayList<>();\n\t\t\t\t\tlistResourceMappers(getApplication().getRootRequestMapper(), resourceMappers);\n\t\t\t\t\tfor (BaseResourceMapper mapper: resourceMappers) {\n\t\t\t\t\t\tBaseResourceMapper baseMapper = (BaseResourceMapper) mapper;\n\t\t\t\t\t\tif (StringUtils.strip(baseMapper.getPath(), \"/\").equalsIgnoreCase(mountPath)) {\n\t\t\t\t\t\t\tif (baseMapper.getResourceReference() instanceof SpriteResourceReference) {\n\t\t\t\t\t\t\t\tscope = baseMapper.getResourceReference().getScope();\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthrow new ExplicitException(\"Path '\" + mountPath \n\t\t\t\t\t\t\t\t\t\t+ \"' should be mounted to a svg sprite resource reference\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (scope == null)\n\t\t\t\t\t\tthrow new ExplicitException(\"Unable to find svg sprite resource mounted at: \" + mountPath);\n\t\t\t\t\t\n\t\t\t\t\tspriteScopes.put(mountPath, scope);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tscope = IconScope.class;\n\t\t\t}\n\t\t} else {\n\t\t\tscope = IconScope.class;\n\t\t\tsymbol = StringUtils.strip(href, \"/\");\n\t\t}\n\t\t\n\t\tString spriteUrl = urlFor(new SpriteResourceReference(scope), new PageParameters()).toString();\n\t\t\n\t\treplaceComponentTagBody(markupStream, openTag, \n\t\t\t\t\"<use xlink:href='\" + spriteUrl + \"#\" + symbol + \"'></use>\");\n\t}\n\n\t@Override","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/web/component/svg/SpriteImage.java#L81-L117","documentation":"OneDev renders SVG icons via SpriteImage, which resolves an icon href of the form '<mountPath>#<symbol>'. At render time it walks the application's request mappers looking for a BaseResourceMapper whose path matches the mountPath and whose resource reference is a SpriteResourceReference. If no mapper is mounted at that path at all, it throws this ExplicitException. The purpose is to fail fast when an icon href points at a sprite resource that was never mounted.","triggerScenarios":"A SpriteImage component (or getVersionedHref) is given an href whose mount path portion (before '#') does not correspond to any mounted resource mapper, e.g. a typo'd path, a path registered with a different mount, or a module providing the sprite that is not initialized/mounted in this instance.","commonSituations":"Customizing icon references in custom pages/branding with a hand-typed sprite path; upgrading OneDev where a sprite mount path changed; writing a plugin that renders icons but forgot to mount its sprite resource reference.","solutions":["Check the href passed to SpriteImage/getVersionedHref and correct the mount path before the '#' to the built-in sprite path (usually leave it empty or use the standard icon scope path).","If it is a custom sprite, mount a SpriteResourceReference at that exact path via a BaseResourceMapper in your application/plugin init.","Verify no leading/trailing slashes or case mismatch: comparison strips slashes but is case-insensitive on path, so normalize the href.","Ensure the plugin/module that provides the sprite mount is installed and enabled."],"exampleFix":"// before\nadd(new SpriteImage(\"icon\", \"/wrong-sprite/path#gear\"));\n// after\nadd(new SpriteImage(\"icon\", \"gear\")); // use default icon scope sprite\n// or mount custom sprite in AppPlugin init:\n// mount(new BaseResourceMapper(\"/my-sprite\", new SpriteResourceReference(MyScope.class)));","handlingStrategy":"validation","validationCode":"// before rendering, verify the sprite mount exists\nString mountPath = href.contains(\"#\") ? StringUtils.strip(href.substring(0, href.indexOf('#')), \"/\") : \"\";\nif (!mountPath.isEmpty()) {\n    List<BaseResourceMapper> mappers = new ArrayList<>();\n    // collect via application root request mapper as SpriteImage does\n    boolean found = mappers.stream().anyMatch(m ->\n        StringUtils.strip(m.getPath(), \"/\").equalsIgnoreCase(mountPath)\n        && m.getResourceReference() instanceof SpriteResourceReference);\n    if (!found) throw new IllegalStateException(\"No svg sprite mounted at: \" + mountPath);\n}","typeGuard":null,"tryCatchPattern":"try {\n    add(new SpriteImage(\"icon\", href));\n} catch (ExplicitException e) {\n    log.warn(\"Bad sprite href '{}', falling back to default icon\", href, e);\n    add(new SpriteImage(\"icon\", defaultSymbol));\n}","preventionTips":["Use SpriteImage.getVersionedHref(null, symbol) or a bare symbol to rely on the default icon scope instead of hand-typed mount paths.","Centralize sprite mount paths in a constant instead of repeating string literals.","When adding custom sprites, mount SpriteResourceReference in plugin init and cover it with a smoke-test page rendering one icon."],"tags":["svg","wicket","resource-mount","onedev"],"backgroundTag":"resource-not-found","analyzedSha":"d44925c47c37992c828ea673a5f9620539bc3ff2","analyzedAt":"2026-09-06T07:18:27.995Z","contentChangedAt":"2026-09-06T07:18:27.995Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}