{"record":{"id":"57ef9c018cb86496","repo":"crowdsecurity/crowdsec","slug":"unable-to-create-folder-s-w-57ef9c","errorCode":null,"errorMessage":"unable to create folder '%s': %w","messagePattern":"unable to create folder '(.+?)': %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/hubtest/scenario.go","lineNumber":55,"sourceCode":"\tif err := os.Symlink(hubDirScenarioPath, scenarioDirParserPath); err != nil {\n\t\tif !os.IsExist(err) {\n\t\t\treturn fmt.Errorf(\"unable to symlink scenario '%s' to '%s': %w\", hubDirScenarioPath, scenarioDirParserPath, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (t *HubTestItem) installScenarioCustomFrom(scenario string, customPath string) (bool, error) {\n\t// we check if its a custom scenario\n\tcustomScenarioPath := filepath.Join(customPath, scenario)\n\tif _, err := os.Stat(customScenarioPath); os.IsNotExist(err) {\n\t\treturn false, nil\n\t}\n\n\titemTypeDirDest := fmt.Sprintf(\"%s/scenarios/\", t.RuntimePath)\n\tif err := os.MkdirAll(itemTypeDirDest, os.ModePerm); err != nil {\n\t\treturn false, fmt.Errorf(\"unable to create folder '%s': %w\", itemTypeDirDest, err)\n\t}\n\n\tscenarioFileName := filepath.Base(customScenarioPath)\n\n\tscenarioFileDest := filepath.Join(itemTypeDirDest, scenarioFileName)\n\tif err := Copy(customScenarioPath, scenarioFileDest); err != nil {\n\t\treturn false, fmt.Errorf(\"unable to copy scenario from '%s' to '%s': %w\", customScenarioPath, scenarioFileDest, err)\n\t}\n\n\treturn true, nil\n}\n\nfunc (t *HubTestItem) installScenarioCustom(scenario string) error {\n\tfor _, customPath := range t.CustomItemsLocation {\n\t\tfound, err := t.installScenarioCustomFrom(scenario, customPath)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/hubtest/scenario.go#L37-L73","documentation":"installScenarioCustomFrom copies a user-authored custom scenario into the test's runtime scenarios directory. Before copying it creates the destination folder (RuntimePath/scenarios/) with os.MkdirAll; failure to create that folder produces this error with the wrapped os cause. It signals a filesystem-level problem creating the runtime scenarios directory.","triggerScenarios":"installScenarioCustom -> installScenarioCustomFrom with an existing custom scenario file, where os.MkdirAll on '<runtime>/scenarios/' fails (permission denied, parent path is a file, read-only fs).","commonSituations":"RuntimePath points inside a read-only mount or a root-owned directory; a file named 'scenarios' exists where the directory should be; invalid characters in the path.","solutions":["Check the wrapped error (usually EACCES or ENOTDIR) and fix permissions on RuntimePath.","Remove/rename any non-directory entry named 'scenarios' under RuntimePath.","Ensure RuntimePath is set correctly in the test item and is writable by the running user.","If running in a container, mount the runtime directory read-write."],"exampleFix":"// before\nRuntimePath: \"/etc/crowdsec\" // owned by root, test runs as user\n// after\nchown -R user:user /etc/crowdsec  # or point RuntimePath to a writable dir","handlingStrategy":"try-catch","validationCode":"if fi, err := os.Stat(runtimePath); err != nil || !fi.IsDir() {\n\treturn fmt.Errorf(\"runtime path %s is not a writable directory\", runtimePath)\n}\nif err := unix.Access(runtimePath, unix.W_OK); err != nil {\n\treturn fmt.Errorf(\"runtime path not writable: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if err := os.MkdirAll(dest, os.ModePerm); err != nil {\n\tif os.IsPermission(err) {\n\t\treturn fmt.Errorf(\"cannot create %s: check ownership/permissions: %w\", dest, err)\n\t}\n\treturn err\n}","preventionTips":["Ensure RuntimePath is owned by the user running the tests.","Check that no file named 'scenarios' occupies the destination path.","Avoid read-only mounts for runtime directories in containers."],"tags":["crowdsec","hub","mkdir","filesystem"],"backgroundTag":"mkdir-permission-denied","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}