submisison.error logs to console but isn't rendered on the page

In this example I see submission.error logs to the console but it doesn't render on the page?
const users: User[] = [];

const getUsers = query((id?: number): Promise<User | User[] | null> => {
return new Promise((resolve, reject) => {
const user = id ? users[id] || null : users;
return setTimeout(() => {
if (user) {
resolve(user);
} else {
reject(new Error("User not found"));
}
}, 3000);
});
}, "getUser");

const isAdmin = action(async (formData: FormData) => {
try {
const id = formData.get("userid");
if (id === "undefined") {
throw new Error("Missing param 'id'");
}
const user = (await getUsers(Number(id))) as User;
if (!user?.admin) throw new Error("User is not admin");
return user;
} catch (e) {
const msg = e instanceof Error ? e.message : "unknown error";
throw new Error(msg);
}
});

export default function Home() {
const users = createAsync(async () => {
const a: User[] = (await getUsers()) as User[];
return a;
});
const sub = useSubmission(isAdmin);

createEffect(() => {
console.log("sub.error", sub.error);
});

return (
<>
<Suspense fallback={<h1>Loading...</h1>}>
<Show when={users()}>
<DisplayUser user={{ name: "dummy", admin: false }} />
</Show>
<Show when={sub.pending}>
<p>Pending</p>
</Show>
<Show when={!sub.pending}>
<Switch>
<Match when={sub.result}>
<p>result: {sub?.result}</p>
</Match>
<Match when={sub.error}>
<p>Error: {sub.error}</p>
</Match>
</Switch>
</Show>
</Suspense>
</>
);
}

function DisplayUser(props: { user: User }) {
return (
<form action={isAdmin} method={"post"}>
<li>
<input name="userid" id="userid" value={props.user.id} />
<button type="submit">isAdmin?</button>
</li>
</form>
);
}
const users: User[] = [];

const getUsers = query((id?: number): Promise<User | User[] | null> => {
return new Promise((resolve, reject) => {
const user = id ? users[id] || null : users;
return setTimeout(() => {
if (user) {
resolve(user);
} else {
reject(new Error("User not found"));
}
}, 3000);
});
}, "getUser");

const isAdmin = action(async (formData: FormData) => {
try {
const id = formData.get("userid");
if (id === "undefined") {
throw new Error("Missing param 'id'");
}
const user = (await getUsers(Number(id))) as User;
if (!user?.admin) throw new Error("User is not admin");
return user;
} catch (e) {
const msg = e instanceof Error ? e.message : "unknown error";
throw new Error(msg);
}
});

export default function Home() {
const users = createAsync(async () => {
const a: User[] = (await getUsers()) as User[];
return a;
});
const sub = useSubmission(isAdmin);

createEffect(() => {
console.log("sub.error", sub.error);
});

return (
<>
<Suspense fallback={<h1>Loading...</h1>}>
<Show when={users()}>
<DisplayUser user={{ name: "dummy", admin: false }} />
</Show>
<Show when={sub.pending}>
<p>Pending</p>
</Show>
<Show when={!sub.pending}>
<Switch>
<Match when={sub.result}>
<p>result: {sub?.result}</p>
</Match>
<Match when={sub.error}>
<p>Error: {sub.error}</p>
</Match>
</Switch>
</Show>
</Suspense>
</>
);
}

function DisplayUser(props: { user: User }) {
return (
<form action={isAdmin} method={"post"}>
<li>
<input name="userid" id="userid" value={props.user.id} />
<button type="submit">isAdmin?</button>
</li>
</form>
);
}
8 Replies
Carl (klequis)
Carl (klequis)OP2w ago
I can also put the console.log in the return and it prints the error
<Match when={sub.error}>
<p>Error: {sub.error}</p>
<p>Log error: {(() => console.log("log error", sub.error))()}</p>
</Match>
<Match when={sub.error}>
<p>Error: {sub.error}</p>
<p>Log error: {(() => console.log("log error", sub.error))()}</p>
</Match>
Typescript, still somewhat new to me, helped me out. I just had to deal with the types returned properly.
Longestlam
Longestlam2w ago
get it to show error message like this:
<Match when={sub.error}>
<p>Error: {sub.error.message}</p>
</Match>
<Match when={sub.error}>
<p>Error: {sub.error.message}</p>
</Match>
https://docs.solidjs.com/solid-router/reference/data-apis/use-submission#error-handling
useSubmission - Solid Router Docs
Documentation for SolidJS, the signals-powered UI framework
Longestlam
Longestlam2w ago
apparently error is type as any so there's no lsp completion:
export type Submission<T, U> = {
readonly input: T;
readonly result?: U;
readonly error: any;
readonly pending: boolean;
readonly url: string;
clear: () => void;
retry: () => void;
};
export type Submission<T, U> = {
readonly input: T;
readonly result?: U;
readonly error: any;
readonly pending: boolean;
readonly url: string;
clear: () => void;
retry: () => void;
};
Madaxen86
Madaxen862w ago
That's a general JS issue because in JS we can throw anything. We could even throw new Date() 😵‍💫 To check if it was throw new Error(... you can if (sub.error instanceOf Error) Then it is typed.
Longestlam
Longestlam2w ago
throw new Date is diabolical lol, but yeah, another reason to return error as value.
Carl (klequis)
Carl (klequis)OP2w ago
console.log is calling .toString() on the error. That is why the message prints in createEffect(() => console.log(sub.error)), but not in the JSX when you do sub.error without the .message.
Madaxen86
Madaxen862w ago
This is JS at its finest 😭
Carl (klequis)
Carl (klequis)OP2w ago
After some reading console.log does a bit more than call toString, which it does some times, but saying it does catches the general idea.

Did you find this page helpful?