{"record":{"id":"4e8a5b02019e80bf","repo":"chenhg5/cc-connect","slug":"claudecode-project-dir-not-found","errorCode":null,"errorMessage":"claudecode: project dir not found","messagePattern":"claudecode: project dir not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agent/claudecode/claudecode.go","lineNumber":731,"sourceCode":"var xmlTagRe = regexp.MustCompile(`<[^>]+>`)\n\nfunc stripXMLTags(s string) string {\n\treturn xmlTagRe.ReplaceAllString(s, \"\")\n}\n\n// GetSessionHistory reads the Claude Code JSONL transcript and returns user/assistant messages.\nfunc (a *Agent) GetSessionHistory(_ context.Context, sessionID string, limit int) ([]core.HistoryEntry, error) {\n\thomeDir, err := os.UserHomeDir()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\ta.mu.RLock()\n\tworkDir := a.workDir\n\ta.mu.RUnlock()\n\tabsWorkDir, _ := filepath.Abs(workDir)\n\tprojectDir := findProjectDir(homeDir, absWorkDir)\n\tif projectDir == \"\" {\n\t\treturn nil, fmt.Errorf(\"claudecode: project dir not found\")\n\t}\n\n\tpath := filepath.Join(projectDir, sessionID+\".jsonl\")\n\tf, err := os.Open(path)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"claudecode: open session file: %w\", err)\n\t}\n\tdefer f.Close()\n\n\tvar entries []core.HistoryEntry\n\tscanner := bufio.NewScanner(f)\n\tscanner.Buffer(make([]byte, 256*1024), 256*1024)\n\n\tfor scanner.Scan() {\n\t\tvar raw struct {\n\t\t\tType      string `json:\"type\"`\n\t\t\tTimestamp string `json:\"timestamp\"`\n\t\t\tMessage   struct {","sourceCodeStart":713,"sourceCodeEnd":749,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/agent/claudecode/claudecode.go#L713-L749","documentation":"GetSessionHistory (agent/claudecode/claudecode.go:731) reads a session transcript from ~/.claude/projects/<encoded-workdir>/. When findProjectDir cannot locate the project directory for the agent's configured work_dir, it throws 'claudecode: project dir not found'. Unlike DeleteSession, it uses the agent's own a.workDir, so this usually reflects a configuration mismatch rather than a bad caller argument.","triggerScenarios":"Calling GetSessionHistory(ctx, sessionID) when no directory under ~/.claude/projects matches the encoded form of the agent's workDir — typically because a.workDir was never set, is relative/unexpanded, or Claude Code has never run in that directory.","commonSituations":"config.toml missing or containing a wrong/relative work_dir for the claudecode agent; running cc-connect with a different HOME than the one where Claude Code stored transcripts; fresh machine with no prior Claude Code usage in that directory; custom CLAUDE_CONFIG_DIR redirecting the projects dir.","solutions":["Set work_dir in the claudecode agent config to the absolute path of the project directory Claude Code was used in.","Confirm ~/.claude/projects/<encoded-dir> exists (encode the abs path the way Claude Code does and stat it).","Ensure the cc-connect process runs with the same HOME as the user who runs Claude Code (systemd/launchd services often run with different HOME).","Check the Claude Code session actually produced a transcript in that directory before querying history."],"exampleFix":"// before (config.toml)\n[agents.claudecode]\nwork_dir = \"~/myproject\"   # relative/tilde — may not resolve as expected\n# after\n[agents.claudecode]\nwork_dir = \"/home/alice/myproject\"  # absolute path matching ~/.claude/projects encoding","handlingStrategy":"validation","validationCode":"home, _ := os.UserHomeDir()\nprojects := filepath.Join(home, \".claude\", \"projects\")\nif st, err := os.Stat(projects); err != nil || !st.IsDir() {\n    return fmt.Errorf(\"claude projects dir missing at %s (has claude code been used?)\", projects)\n}","typeGuard":null,"tryCatchPattern":"entries, err := agent.GetSessionHistory(ctx, id)\nif err != nil && strings.Contains(err.Error(), \"project dir not found\") {\n    return nil, fmt.Errorf(\"no Claude Code history for this workspace; check work_dir config\")\n}","preventionTips":["Configure work_dir as an absolute path matching the directory used with Claude Code.","Ensure the cc-connect service runs with the correct HOME (systemd/launchd override HOME!).","Run `claude` once in the target directory so ~/.claude/projects/<dir> is created.","Watch for custom CLAUDE_CONFIG_DIR setups that move the projects directory."],"tags":["claudecode","configuration","session-history"],"backgroundTag":"directory-not-found","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}