{"record":{"id":"0ea3c775c4a251bd","repo":"charmbracelet/crush","slug":"failed-to-resolve-workspace-path-w","errorCode":null,"errorMessage":"failed to resolve workspace path: %w","messagePattern":"failed to resolve workspace path: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/backend/backend.go","lineNumber":356,"sourceCode":"// parameters, or returns an existing workspace if one already exists at\n// the same resolved path (first-wins semantics).\n//\n// args.ClientID must be a valid UUID identifying the calling client;\n// the resulting workspace registers a creation hold on behalf of that\n// client which is released either by the first SSE attach (which\n// converts it into a stream claim) or by the grace window expiring.\nfunc (b *Backend) CreateWorkspace(args proto.Workspace) (*Workspace, proto.Workspace, error) {\n\tif args.Path == \"\" {\n\t\treturn nil, proto.Workspace{}, ErrPathRequired\n\t}\n\tclientID, err := validateClientID(args.ClientID)\n\tif err != nil {\n\t\treturn nil, proto.Workspace{}, err\n\t}\n\n\tkey, err := resolveWorkspaceKey(args.Path)\n\tif err != nil {\n\t\treturn nil, proto.Workspace{}, fmt.Errorf(\"failed to resolve workspace path: %w\", err)\n\t}\n\n\tb.mu.Lock()\n\tif err := b.admitLocked(clientID); err != nil {\n\t\tb.mu.Unlock()\n\t\treturn nil, proto.Workspace{}, err\n\t}\n\t// A client is arriving: cancel any pending idle shutdown so we never\n\t// hand back a workspace on a server that is about to tear itself down.\n\tb.cancelShutdownLocked()\n\tif existingID, ok := b.pathIndex[key]; ok {\n\t\tif ws, found := b.workspaces.Get(existingID); found {\n\t\t\t// Hold b.mu while registering: teardown also\n\t\t\t// acquires b.mu before tearing the workspace\n\t\t\t// down, so this guarantees the workspace we\n\t\t\t// return cannot be torn out from under us\n\t\t\t// between lookup and registerClient. Lock order\n\t\t\t// here is b.mu -> ws.clientsMu.","sourceCodeStart":338,"sourceCodeEnd":374,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/backend/backend.go#L338-L374","documentation":"CreateWorkspace resolves the caller-supplied workspace path via resolveWorkspaceKey before registering it in the backend's dedupe map. Any failure resolving (e.g. empty path, evaluation/symlink/stat failure) is wrapped with this message and aborts workspace creation.","triggerScenarios":"Calling Backend.CreateWorkspace with args.Path that is empty, does not exist, cannot be made absolute, or fails symlink/stat resolution.","commonSituations":"Passing a relative path from a different working directory; pointing at a deleted directory; symlink to a missing target; running the client from a container with a non-mounted path.","solutions":["Pass an existing, absolute directory path as args.Path","Create the directory before calling CreateWorkspace","Fix broken symlinks or mount the path into the environment"],"exampleFix":"// before\nb.CreateWorkspace(ctx, proto.CreateWorkspaceArgs{Path: \"\"})\n// after\nabs, _ := filepath.Abs(\"/home/user/project\")\nos.MkdirAll(abs, 0o755)\nb.CreateWorkspace(ctx, proto.CreateWorkspaceArgs{Path: abs})","handlingStrategy":"validation","validationCode":"func ensureWorkspacePath(p string) error {\n    if p == \"\" {\n        return errors.New(\"workspace path is empty\")\n    }\n    abs, err := filepath.Abs(p)\n    if err != nil {\n        return err\n    }\n    fi, err := os.Stat(abs)\n    if err != nil {\n        return fmt.Errorf(\"workspace path %q: %w\", abs, err)\n    }\n    if !fi.IsDir() {\n        return fmt.Errorf(\"%q is not a directory\", abs)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"ws, err := b.CreateWorkspace(ctx, args)\nif err != nil && strings.Contains(err.Error(), \"failed to resolve workspace path\") {\n    return fmt.Errorf(\"cannot open workspace: %w\", err)\n}","preventionTips":["Pass absolute, existing directory paths to CreateWorkspace","Stat/symlink-resolve the path client-side before calling","Create the project directory before opening a workspace on it"],"tags":["filesystem","workspace","path"],"backgroundTag":"invalid-path","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}