# Works Locally, Fails on Submission (Formatting Issue?)

**URL:** <https://forum.codecrafters.io/t/works-locally-fails-on-submission-formatting-issue/15439>\
**Category:** Challenges\
**Tags:** challenge:shell\
**Created:** [October 26, 2025, 4:28pm UTC](https://forum.codecrafters.io/t/works-locally-fails-on-submission-formatting-issue/15439 "2025-10-26T16:28:19Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![E1gocn](https://yyz1.discourse-cdn.com/flex003/user_avatar/forum.codecrafters.io/e1gocn/32/14273_2.png) [@E1gocn](https://forum.codecrafters.io/u/E1gocn)\
**Post date:** [October 26, 2025, 4:28pm UTC](https://forum.codecrafters.io/t/works-locally-fails-on-submission-formatting-issue/15439/1 "2025-10-26T16:28:20Z")

</div>

Yesterday, I completed 22 of 43 stages. I planned to redo the autocompletion part from scratch, so I paused. Today I updated my code, but the redirection stage is failing. After some research, I found that formatting differs across OSs — on my MacBook Air, I got the desired results.

Could my code be picking up the wrong `ls`? Logs are attached below.

```bash
[tester::#UN3] Running tests for Stage #UN3 (Redirection - Append stderr)
[tester::#UN3] [setup] export PATH=/tmp/blueberry/apple/blueberry:$PATH
[tester::#UN3] Running ./your_program.sh
[your-program] $ ls -1 nonexistent >> /tmp/qux/bar.md
[your-program] ls: cannot access 'nonexistent': No such file or directory
[tester::#UN3] ^ Line does not match expected value.
[tester::#UN3] Expected: "ls: nonexistent: No such file or directory"
[tester::#UN3] Received: "ls: cannot access 'nonexistent': No such file or directory"
[your-program] $ 
[tester::#UN3] Assertion failed.
[tester::#UN3] Test failed (try setting 'debug: true' in your codecrafters.yml to see more details)

```

Here’s the code which handles non-builtin commands:

```c

void exec_external(char **argv, struct exec_info** execs, int n_exc) {
    struct exec_info *ei = find_exec(argv[0], execs, n_exc);
    if (strcmp(argv[0], "ls") == 0) {
        printf("%s\n", ei->e_path);
    }
    if (ei == NULL) {
        printf("%s: command not found\n", argv[0]);
        return;
    }
    pid_t pid;

    if ((pid = fork()) < 0) {
        perror("fork");
        exit(1);
    } else if (pid == 0) {
        execv(ei->e_path, argv);
    } else {    
        if (waitpid(pid, NULL, 0) != pid) {
            perror("waitpid");
            exit(1);
        }
    }
}

```

The parser remains unchanged. My current idea is to, before entering the REPL loop, traverse all the paths, locate all executables, and store them in a structure like this:

```c
struct exec_info {
    char *e_name;
    int e_len;
    char *e_path;
};

```

Each entry will be dynamically allocated — `e_name` for the executable name, `e_len` for its length, and `e_path` for the absolute path. I’ll then perform a binary search to quickly retrieve the associated data and work with it as needed.

> ```c
> 
> #include "exec.h"
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> #include <dirent.h>
> #include <unistd.h>
> 
> int exec_compare_sort(const void *a, const void *b) {
> const struct exec_info *ea = *((const struct exec_info**)a);
> const struct exec_info *eb = *((const struct exec_info**)b);
> return strcmp(ea->e_name, eb->e_name);
> }
> 
> int exec_compare_bin_search(const void *key, const void *elem) {
> const struct exec_info *e_key = (const struct exec_info*)key;
> const struct exec_info *e_elem = *((const struct exec_info**)elem);
> return strcmp(e_key->e_name, e_elem->e_name);
> }
> 
> struct exec_info *find_exec(char *name, struct exec_info **execs, int n_exc) {
> struct exec_info key = {
> .e_name = name,
> .e_len = strlen(name),
> .e_path = NULL
> };
> struct exec_info **res = bsearch(&key, execs, n_exc, sizeof(struct exec_info*), exec_compare_bin_search);
> return res ? *res : NULL;
> }
> 
> struct exec_info **build_exec_list(char**paths, int n_paths, int *n_exc, int *mx_len) {
> int cap = 16, len = 0, tmp_len = 0;
> 
> struct exec_info **exc_list = malloc(cap * sizeof(struct exec_info*));
> 
> char *built_in[] = {"echo", "pwd", "cd", "exit", "type"};
> 
> for (int i = 0; i < 5; i++) {
> exc_list[len] = malloc(sizeof(struct exec_info));
> exc_list[len]->e_name = strdup(built_in[i]);
> exc_list[len]->e_len = strlen(built_in[i]);
> exc_list[len++]->e_path = strdup("-");
> }
> 
> for (int i = 0; i < n_paths; i++) {
> DIR *d = opendir(paths[i]);
> if (!d) continue;
> 
> struct dirent *di;
> while ((di = readdir(d)) != NULL) {
> if (di->d_name[0] == '.' || di->d_type == DT_DIR) continue;
> 
> int okay = 1;
> for (int i = 0; i < 5; i++) {
> if (strcmp(built_in[i], di->d_name) == 0) {
> okay = 0;
> break;
> }
> }
> if (!okay) continue;
> 
> char full[256];
> sprintf(full, "%s/%s", paths[i], di->d_name);
> if (access(full, F_OK | X_OK) == 0) {
> if (len == cap) {
> cap *= 2;
> exc_list = realloc(exc_list, cap * sizeof(struct exec_info*));
> }
> int l = strlen(di->d_name);
> if (l > tmp_len) {
> tmp_len = l;
> }
> exc_list[len] = malloc(sizeof(struct exec_info));
> exc_list[len]->e_name = strdup(di->d_name);
> exc_list[len]->e_len = l;
> exc_list[len++]->e_path = strdup(full);
> }
> }
> closedir(d);
> }
> *mx_len = tmp_len;
> *n_exc = len;
> 
> qsort(exc_list, len, sizeof(struct exec_info*), exec_compare_sort);//sort for auto-completion
> 
> return exc_list;
> }
> 
> ```
> 
> }

---

<div class="post-metadata">

**Author:** ![andy1li](https://yyz1.discourse-cdn.com/flex003/user_avatar/forum.codecrafters.io/andy1li/32/10_2.png) [@andy1li](https://forum.codecrafters.io/u/andy1li)\
**Post date:** [October 26, 2025, 8:12pm UTC](https://forum.codecrafters.io/t/works-locally-fails-on-submission-formatting-issue/15439/3 "2025-10-26T20:12:45Z")

</div>

Hey @E1gocn, could you [upload your code to GitHub](https://docs.codecrafters.io/features/publish-to-github) and share the link? It will be much easier to debug if I can run it directly.

---

<div class="post-metadata">

**Author:** ![E1gocn](https://yyz1.discourse-cdn.com/flex003/user_avatar/forum.codecrafters.io/e1gocn/32/14273_2.png) [@E1gocn](https://forum.codecrafters.io/u/E1gocn)\
**Post date:** [October 27, 2025, 2:03am UTC](https://forum.codecrafters.io/t/works-locally-fails-on-submission-formatting-issue/15439/4 "2025-10-27T02:03:46Z")

</div>

> **[GitHub - E1gocn/codecrafters-shell-c](https://github.com/E1gocn/codecrafters-shell-c)**
>
> Contribute to E1gocn/codecrafters-shell-c development by creating an account on GitHub.

---

<div class="post-metadata">

**Author:** ![andy1li](https://yyz1.discourse-cdn.com/flex003/user_avatar/forum.codecrafters.io/andy1li/32/10_2.png) [@andy1li](https://forum.codecrafters.io/u/andy1li)\
**Post date:** [October 27, 2025, 5:02am UTC](https://forum.codecrafters.io/t/works-locally-fails-on-submission-formatting-issue/15439/6 "2025-10-27T05:02:11Z")

</div>

@E1gocn I tried running your code against the previous stages, but it’s actually no longer passing a previous stage **#MG5 (Locate executable files)**.

 ![image](https://canada1.discourse-cdn.com/flex003/uploads/codecrafters/original/3X/1/9/19fd597873e4f387ce251adface050d7835e34d5.png)

**Suggestions** :

1. Use [our CLI](https://docs.codecrafters.io/cli/installation) to test against previous stages by running:

```auto
codecrafters test --previous

```

1. Focus on fixing the early stages first, as later stages depend on them.

Let me know if you’d like help debugging this one!

---

<div class="post-metadata">

**Author:** ![E1gocn](https://yyz1.discourse-cdn.com/flex003/user_avatar/forum.codecrafters.io/e1gocn/32/14273_2.png) [@E1gocn](https://forum.codecrafters.io/u/E1gocn)\
**Post date:** [October 27, 2025, 10:18am UTC](https://forum.codecrafters.io/t/works-locally-fails-on-submission-formatting-issue/15439/8 "2025-10-27T10:18:11Z")

</div>

```bash
[tester::#MG5] Running tests for Stage #MG5 (Locate executable files)
[tester::#MG5] [setup] export PATH=/tmp/bar:$PATH
[tester::#MG5] [setup] export PATH=/tmp/baz:$PATH
[tester::#MG5] [setup] export PATH=/tmp/qux:$PATH
[tester::#MG5] [setup] PATH is now: /tmp/qux:/tmp/baz:/tmp/bar:/vcpkg:...
[tester::#MG5] [setup] Available executables:
[tester::#MG5] [setup] - my_exe
[tester::#MG5] Running ./your_program.sh
[your-program] $ type cat
[your-program] cat is /bin/cat
[tester::#MG5] ^ Line does not match expected value.
[tester::#MG5] Expected: "cat is /usr/bin/cat"
[tester::#MG5] Received: "cat is /bin/cat"
[your-program] $ 
[tester::#MG5] Assertion failed.
[tester::#MG5] Test failed (try setting 'debug: true' in your codecrafters.yml to see more details)

```

My program does print output, but it’s wrong — it finds `cat`, yet the path it shows isn’t correct. I’m not sure why, since I never changed or modified the paths manually. I just went through each directory in the PATH variable, looked for executables, and saved their paths in `e_path`. I didn’t strip, append, or index anything, so I don’t understand how the paths ended up mismatched.

```c

    char *env_path = strdup(getenv("PATH"));
    char *env_home = strdup(getenv("HOME"));

    char *paths[128];
    size_t n_paths = 0;

    char *tmp = strtok(env_path, ":");
    while (tmp != NULL) {
        paths[n_paths++] = tmp;
        tmp = strtok(NULL, ":");
    }
    paths[n_paths] = NULL;

```

```c
//line 61-62 exec.c
char full[256];
sprintf(full, "%s/%s", paths[i], di->d_name);

```

```c
//line 72-75 exec.c
                exc_list[len] = malloc(sizeof(struct exec_info));
                exc_list[len]->e_name = strdup(di->d_name);
                exc_list[len]->e_len = l;
                exc_list[len++]->e_path = strdup(full);

```

---

<div class="post-metadata">

**Author:** ![E1gocn](https://yyz1.discourse-cdn.com/flex003/user_avatar/forum.codecrafters.io/e1gocn/32/14273_2.png) [@E1gocn](https://forum.codecrafters.io/u/E1gocn)\
**Post date:** [October 27, 2025, 1:18pm UTC](https://forum.codecrafters.io/t/works-locally-fails-on-submission-formatting-issue/15439/9 "2025-10-27T13:18:38Z")

</div>

I found the root cause. I wasn’t aware that the **POSIX standard** specifies that when a command name isn’t a shell builtin, the shell must **search each directory in `$PATH` from left to right** until it finds an executable with that name.

My previous binary search ignored the `$PATH` order and could return any matching entry, regardless of its position in `$PATH`. After adjusting the lookup logic to respect the path order, it now works correctly.

---

<div class="post-metadata">

**Author:** ![system](https://canada1.discourse-cdn.com/flex003/uploads/codecrafters/original/3X/7/0/700657133935c15703e22c7c8870394f6e6dc27d.svg) [@system](https://forum.codecrafters.io/u/system)\
**Post date:** [November 1, 2025, 1:18pm UTC](https://forum.codecrafters.io/t/works-locally-fails-on-submission-formatting-issue/15439/10 "2025-11-01T13:18:44Z")

</div>

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.
